deathbygoats has asked for the wisdom of the Perl Monks concerning the following question:

i'm creating a script that adds users to LDAP from a text file containing their name and other information. i want to create unique UID numbers for each user. what would be the best way to do this? the only way i can think is to have a separate file containing the uid number that would be incremented every time a user is added. is there any way i could store this number in my perl script itself? the script is for someone else and i'd like for it to be as self-contained as possible. basically i want to know if i can store a number within my script and actually increment it every time a user is added, so it would basically be changing itself every time.

Considered by holli - retitle: "create uniqe user id" (nothing to do with script changing it own code.)
Unconsidered by castaway - Keep/Edit/Delete: 15/16/1 - Yes it does

Replies are listed 'Best First'.
Re: can a script change itself?
by ikegami (Patriarch) on Mar 24, 2005 at 15:07 UTC

    Data::UUID will create a unique number, without having to know which id was last assigned. The number might be too big for you, though.

    Update: This module is a standard implementation of jZed's suggestion.

Re: can a script change itself?
by sweetblood (Prior) on Mar 24, 2005 at 15:07 UTC
      Inline::Files sounds like a good idea. the UID number attribute will be used for the posixAccount object class (unix logins), so i'm pretty sure it actually has to be a number. using an ancillary file would've been my other option, although i think if i can store the uid in the script it might be the most convenient.
        Wait a tic...the last time I added Unix accounts, I don't remember the need to specify a UID. The system takes care of this automatically. Am I missing something?

        thor

        Feel the white light, the light within
        Be your own disciple, fan the sparks of will
        For all of us waiting, your kingdom will come

A script can change itself
by ktross (Deacon) on Mar 24, 2005 at 16:21 UTC
    There are better ways of doing this, but yes, a script can change itself. Here is a self modifying script that keeps track of the number of times it is called.
    # Get current file name $filename = __FILE__; # get old UID stored after __END__ $uid = <DATA>; chomp($uid); print "This script has been run $uid times $/"; # increment UID $uid++; # open current running file open(THIS_IN, $filename) or die "Could not open file"; @code = <THIS_IN>; close (THIS_IN); # Store new UID in last line of this code $size = @code; @code[$size-1]=$uid; # open current running file open(THIS_OUT,"> $filename") or die "Could not output to file"; print THIS_OUT @code; close (THIS_OUT); __END__ 0
    This is presented mostly for interest, as I am from the school of thought that self-modification is bad. It can lead to some very hard to track down bugs.
      The idea is great and it works nicely, but only if you are sure that you are the only user of this script. It will not work in a web-server environment or --heaven forbid-- in a mod_perl environment for instance where this same script could be called by more than one client at the same time as it has no protection against such classical race conditions.

      I know "multiple concurrent user safety" wasn't part of the specs of this question, but I thought it would be good to give a word of warning here anyhow. I've been bitten before by race conditions when using cook-book (aka cut-and-paste) style programming before.

      CountZero

      "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

        I know "multiple concurrent user safety" wasn't part of the specs of this question, but I thought it would be good to give a word of warning here anyhow. I've been bitten before by race conditions when using cook-book (aka cut-and-paste) style programming before.

        I learned one lesson in my intro to concurrency course: "Concurrency is hard." There are few, if any, concurrent debuggers in existance ( one grad student was working on one, with some limited success), and the very convenient rule that states "if I run the same program, with the same inputs, I'll get the same output" goes out the window, because other programs can interfere.

        Avoid concurent programs when you can: when you can't, swear loudly and quadruple your delivery date.
        --
        Ytrew

Re: can a script change itself?
by jZed (Prior) on Mar 24, 2005 at 15:04 UTC
    You probably could do some jiggery-pokery with $0, but it sounds like a mess. Why not just create UIDs on the fly e.g. from time-in-seconds + large random number + process id.
Re: can a script change itself?
by perlfan (Parson) on Mar 24, 2005 at 15:43 UTC
    If it does not have to increment, you can do:
    my $id = crypt($firstname,$lastname);
    Where "$firstname" is 'crypted' using "$lastname" as the salt. I wouldn't use to this to store any passwords, but it is way to calculate (and retrieve) their record in the future by being able to predict their id rather than searching for them. You could also use md5.
      Well, if the OP was satisfied to have unique strings, he could have taken the $firstname.$lastname in the first place. Which actually has a better chance of being unique than your suggestion - as it will return the same string for "John Black" and "John Blueberry".
Re: can a script change itself?
by FitTrend (Pilgrim) on Mar 24, 2005 at 15:05 UTC

    If your on windows, you could store it in the registry and then call it each time you need it within your perl file.

    Optionally you can use any database module from CPAN to save this data to a database DBD::SQLite, DBD::MySQL, DBI, etc.

    Hope this helps

Re: can a script change itself?
by satchm0h (Beadle) on Mar 24, 2005 at 15:33 UTC
    You could just use an ancillary file:

    use strict; my $uuid_store = '/tmp/.uuid_store'; my $MY_UID=1; if (-e $uuid_store) { open INHANDLE, "<$uuid_store" || die "Can't open $uuid_store for r +ead\n"; my $var = <INHANDLE>; close INHANDLE; $MY_UID = int $var; } print "The uid you are looking for : $MY_UID\n"; open OUTHANDLE, ">$uuid_store" || die "Can't open $uuid_store for writ +e\n"; print OUTHANDLE ++$MY_UID; close OUTHANDLE;

    Output:

    % perl gen_uid.pl The uid you are looking for : 1 % perl gen_uid.pl The uid you are looking for : 2 % perl gen_uid.pl The uid you are looking for : 3 % perl gen_uid.pl The uid you are looking for : 4 % perl gen_uid.pl The uid you are looking for : 5 % perl gen_uid.pl The uid you are looking for : 6
Re: can a script change itself?
by thekestrel (Friar) on Mar 24, 2005 at 16:29 UTC
    Hi,
    Just for the sake of putting it in the same file, I guess you could open the script and append a comment like '#NEXT_UID=<num>'. Then when the script runs you can just replace the value. That way you can also do it with more than one variable as it is named. This isn't the prettiest code, but it works =P.
    #!/usr/bin/perl use strict; use warnings; sub get_next_number { open FILE, "<$0" or die "1:Could not open file : $!\n"; my @lines = <FILE>; my $n = $1 if ( @lines[scalar @lines - 1] =~ /#NEXT_UID=(\d+)/ ); my $m = $n + 1; pop @lines; push @lines, "#NEXT_UID=$m\n"; close (FILE); open FILE, "+<$0" or die "2:Could not open file : $!\n"; print FILE $_ foreach @lines; close (FILE); return $n; } my $num; $num = get_next_number(); print "Next available number is : $num\n"; $num = get_next_number(); print "Next available number is : $num\n"; #NEXT_UID=14


    Regards Paul
    Update:ktross beat me to the punch with the same idea =P.
    Cleaned code a little and made it so you can now have multiple variables and have them anywhere in the file also...Version 2 =P
    #!/usr/bin/perl use strict; use warnings; #My changeable variables #NEXT_UID=38 #NEXT_FLUFFY=6 sub get_next_number { my $var = shift; my $n = -1; open FILE, "<$0" or die "1:Could not open file : $!\n"; my @lines = <FILE>; close (FILE); for my $linenum ( 1 .. scalar @lines - 1 ) { if ( $lines[$linenum] =~ /#$var=(\d+)/ ) { $n = $1; my $m = $n + 1; $lines[$linenum] = "#$var=$m\n"; open FILE, ">$0" or die "2:Could not open file : $!\n"; print FILE $_ foreach @lines; close (FILE); } } return $n; } my $num; $num = get_next_number("NEXT_UID"); print "Next available number is : $num\n"; $num = get_next_number("NEXT_FLUFFY"); print "Next available number is : $num\n";
Re: can a script change itself?
by mojotoad (Monsignor) on Mar 24, 2005 at 19:54 UTC
    Why do you want to create a unique UID?

    When you create an LDAP entry, it is assigned a Distinguished Name attribute (DN) -- this is a unique identifier for that LDAP entry.

    The LDAP server itself has these DN's stored at that point, there's no reason to store them separately for your script -- they can be retreived at any time.

    However, if you're dead set on storing unique identifiers, store the DN's in a hash for later reference. I like to use Data::Dumper to dump the hash into a data file for later reference and update.

    Cheers,
    Matt

      • Well, if you use "cn=surname firstname,ou=..." as a DN, there might be the problem if there are two persons with the same name in the same ou... so an additional really unique id might be helpful (at least to make DN really unique): "cn=surname firstname uniqueid,ou=..." (or even think about using this uniqueId as cn... but that might cause problems with certificates...)
      • If you want to do a periodic data synchronisation to different data sources, you need something constant... and a person's name doesn't need to be constant (e.g. in case of marriage).. so for meta directories, I often add a unique attribute to the ldap object which can also be copied to other data sources to get a link to objects in that directory

      The way I prefer to use is to enhance the ldap schema by another objectclass (e.g. lastUniqueIdentifier) which contains among others the attribute an attribut where the last used unique identifier is saved (e.g. lastUniqueUID). This way I can use it from several synchronisation jobs...

      Best regards,
      perl -e "s>>*F>e=>y)\*martinF)stronat)=>print,print v8.8.8.32.11.32"

        From the perl LDAP FAQ:

        Every entry in a directory has a Distinguished Name, or DN. It is a unique Entry identifier throughout the complete directory. No two Entries can have the same DN within the same directory.

        On the other hand, a relative distinguished name (RDN):

        Every DN is made up of a sequence of Relative Distinguished Names, or RDNs. The sequences of RDNs are separated by commas (,). In LDAPv2 semi-colons (;) were also allowed. There can be more than one identical RDN in a directory, but they must have different parent entries.

        I see your second point. However, I suppose it depends on how you're handling records -- in the event of marriage, for example, you could look at it as one LDAP entry being deleted and a new one created. That's fine if you don't care about tracking the history of name changes.

        Cheers,
        Matt