Bulk Provisioning

Revision as of 00:18, 9 February 2007 by Dlbewley (talk | contribs) (tool to migrate aliases)


Zmprov Command Files

The zmprov command will accept commands from a file. Just pass the commands in on standard input like this:

 zmprov < mydata.zmp

Below are some ways to create a command file from your existing account data.

Create Accounts

Passwd File to Zmprov

Following is a perl script to take a passwd file and turn it into a zmprov command file for account provisioning.

#!/usr/bin/perl
################################################################################
# $Id: passwd2zmprov,v 1.1.1.1 2007/01/23 18:04:38 dlbewley Exp $
#-------------------------------------------------------------------------------
# Description:
#   Tool to create commands suitable for zmprov from a unix passwd file.
#   We don't use getpwent etc., because we are likely working on a copy.
#
# See Also:
#   http://wiki.zimbra.com/index.php?title=Bulk_Create
#
# Usage:
#    ./passwd2zmprov /etc/passwd > users.zmp
#    zmprov < users.zmp
################################################################################

my $DOMAIN='hostname.foo.bar'; # zimbra installation domain name
my $MIN_UID=500;  # skip system accounts like httpd
my $MAX_UID=5000; # skip other system accounts like nfsnobody
my $PASSWORD='password'; # default password
# Zimbra Class Of Service for users
my $COS_ID = 'e00000a0-0c00-00d0-000a-000d00afea0a'; # use during testing only
#my $COS_ID = `su - zimbra -c 'zmprov gc Default |grep zimbraId:'`;
#$COS_ID =~ s/zimbraId:\s*|\s*$//g;


while(<>) {
    chomp;
    my ($uname,$x,$uid,$gid,$gecos,$dir,$shell) = split(/:/);
    if (! ($MIN_UID < $uid && $uid < $MAX_UID)) {
        warn "skipping $uname, $uid not between $MIN_UID and $MAX_UID";
        next;
    }

    my $date = localtime(time);
    my ($fullname,$description) = split(/\s*,\s*/,$gecos,2);
    my ($fname,$initial,$lname) = split(/\s+/,$fullname);
    if (! $lname) {
        $lname = $initial;
        undef $initial;
    }
    my $displayname = "$fname $initial $lname";
    $displayname =~ s/\s+/ /;

    print qq{ca $uname\@$DOMAIN "$PASSWORD"\n};
    print qq{ma $uname\@$DOMAIN zimbraCOSid "$COS_ID"\n};
    print qq{ma $uname\@$DOMAIN givenName "$fname"\n};
    print qq{ma $uname\@$DOMAIN sn "$lname"\n};
    print qq{ma $uname\@$DOMAIN cn "$uname"\n};
    print qq{ma $uname\@$DOMAIN displayName "$displayname"\n};
    print qq{ma $uname\@$DOMAIN description "$description"\n};
    print qq{ma $uname\@$DOMAIN zimbraNotes "Migrated $date"\n};
    print qq{ma $uname\@$DOMAIN zimbraPasswordMustChange TRUE\n};
    print qq{\n};
}

To execute:

 perl passwd2zmprov < passwd > mydata.zmp

CSV File to Zmprov

Following is a simple perl script to take a CSV file and turn it into the correct zmprov commands

#!/usr/bin/perl
 
# Lookup the valid COS (Class of Service) ID in the interface or like this
my $cosid = `su - zimbra -c 'zmprov gc Default |grep zimbraId:'`;
$cosid =~ s/zimbraId:\s*|\s*$//g;
  
while (<>) {
       chomp;
 
       # CHANGE ME: To the actual fields you use in your CSV file
       my ($email, $password, $first, $last) = split(/\,/, $_, 4);
         
       my ($uid, $domain) = split(/@/, $email, 2);
 
       print qq{ca $uid\@$domain $password\n};
       print qq{ma $uid\@$domain zimbraCOSid "$cosid"\n};
       print qq{ma $uid\@$domain givenName "$first"\n};
       print qq{ma $uid\@$domain sn "$last"\n};
       print qq{ma $uid\@$domain cn "$uid"\n};
       print qq{ma $uid\@$domain displayName "$first $last"\n};
       print qq{ma $uid\@$domain zimbraPasswordMustChange TRUE\n};
       print qq{\n};
}

The above is only a starting place, you will need to change other options (eg: the zimbraPasswordMustChange is an example only) and of course how you create and split the input data.

Also, some CSV files may contain quotes you want to remove.


Create Aliases

Aliases File to Zmprov

#!/usr/bin/perl
################################################################################
# $Id: aliases2zmprov,v 1.2 2007/02/09 00:11:34 dlbewley Exp $
#-------------------------------------------------------------------------------
# Description:
#   Tool to create commands suitable for zmprov from a unix aliases file.
#   Handles the case of an :include: construct.
#   Handles the case of multiple recipients for an alias by making a dist list.
#   - A Zimbra alias must be associated with exactly one Zimbra account.
#   - A Zimbra distribution list may contain users on remote hosts.
#
# See Also:
#   http://wiki.zimbra.com/index.php?title=Bulk_Create
#
# Usage:
#    ./aliases2zmprov /etc/aliases 1> aliases.zmp 2> aliases.err
#    zmprov < aliases.zmp
#
################################################################################

my @CNAME_SKIP= qw( ftp news postmaster root webmaster );
my @ALIAS_SKIP= qw( abuse mailer-daemon postmaster  );
my $DOMAIN = 'hostname.foo.bar';

use File::Basename;

while(<>) {
    chomp;
    s/#.*$//; # skip comments
    next if /^\s*$/; # skip blank lines

    my @cnames;
    my ($alias,$cname) = split(/:/,$_,2);

    $alias =~ s/\s*//g;
    # scrutinize the aliases
    if (grep /^$alias$/, @ALIAS_SKIP) {
        warn "skipping alias $alias -> $cname";
        next;
    }

    $cname =~ s/\s*//g;

    # scrutinize the canonical names
    if ($cname =~ m/:include:/) {
        # need to pull in contents of file and make a dist
        # list instead of an alias
        my $fullfile = $cname;
        $fullfile =~ s/:include://;
        my ($file,$path) = fileparse($fullfile);
        if (! -e $file) {
            warn "WARNING skipping $alias -> $cname Please run 'scp mail:$fullfile .'";
            next; # go to next line of aliases file
        } else {
            # process include file
            open(F,$file) || warn "Can not read $file";
            while (<F>) {
                chomp;
                s/#.*$//; # skip comments
                next if /^\s*$/; # skip blank lines
                push @cnames, $_;
            }
        }
        #next; # go to next line of aliases file
    }
    if ($cname =~ m/,/) {
        # multiple recipients make this a list instead of an alias
        @cnames = split(/,/,$cname);
    }
    # if more than one cname then it is a dist list
    if (length($cnames[0])) {
        print "cdl $alias\@$DOMAIN\n";
        foreach my $member (@cnames) {
            # skip aliases to certain users
            if (grep /^$member$/, @CNAME_SKIP) {
                warn "skipping cname $member <- $alias";
                next; # go to next member
            }
            # A Zimbra distribution list may contain users on remote hosts.
            if ($member =~ m/\@/) {
                print "adlm $alias\@$DOMAIN $member\n";
            } else {
                print "adlm $alias\@$DOMAIN $member\@$DOMAIN\n";
            }
        }
        @cnames=();
        next; # go to next line of aliases file
    }

    # A Zimbra alias must be associated with exactly one Zimbra account.
    if ($cname =~ m/\@/) {
        # alias to remote host. this could be created as a dist list with 1 member
        # that seems undersirable though.
        warn "WARNING skipping cname $cname <- $alias it is a not here - TODO";
        next; # go to next line of aliases file
    }
    if ($cname =~ m/\/|\|/) {
        # alias to a file or a program. don't try to accomodate
        warn "WARNING skipping cname $cname <- $alias it is a file or pipe";
        next;
    }

    # skip aliases to certain users
    if (grep /^$cname$/, @CNAME_SKIP) {
        warn "skipping cname $cname <- $alias";
        next;
    }

    # are we sure $cname\@$DOMAIN exists?
    print "aaa $cname\@$DOMAIN $alias\@$DOMAIN\n";
}
# example data
__DATA__
admin: root
dudes: me,you
postmaster: sarah
wax: :include:/etc/mail/lists/wax.list
jon.doe: jdoe
Jump to: navigation, search