Initial commit, everything appears to work
This commit is contained in:
147
README.md
Normal file
147
README.md
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
cmdarg
|
||||||
|
======
|
||||||
|
|
||||||
|
cmdarg is a helper library I wrote for bash scripts because, at current, option parsing in bash (-foo bar, etc) is really hard, lots harder than it should be, given bash's target audience. So here's my solution. There are 4 functions you will care about:
|
||||||
|
|
||||||
|
cmdarg
|
||||||
|
cmdarg_info
|
||||||
|
cmdarg_parse
|
||||||
|
cmdarg_usage
|
||||||
|
|
||||||
|
cmdarg
|
||||||
|
======
|
||||||
|
|
||||||
|
This function is used to tell the library what command line arguments you accept. Check cmdarg.sh for the latest syntax.
|
||||||
|
|
||||||
|
cmdarg 'l:' 'source_ldap' 'Source (old) LDAP URI'
|
||||||
|
cmdarg 'u:' 'source_ldap_username' 'Source (old) LDAP Username'
|
||||||
|
cmdarg 'c:' 'groupmap' 'A CSV file mapping usernames to groups that they should belong to post-conversion' '' 'test -e $OPTARG'
|
||||||
|
|
||||||
|
All arguments are OPTIONAL by default. An argument that has ':' on the end of its single character option, and does not specify a default value (empty string is considered "not specified"), is REQUIRED.
|
||||||
|
|
||||||
|
cmdarg_info
|
||||||
|
===========
|
||||||
|
|
||||||
|
This function sets up information about your program for use when printing the help/usage message. Again, see cmdarg.sh for the latest syntax.
|
||||||
|
|
||||||
|
cmdarg_info "header" "Convert existing LDAP users to the new LDAP server/schema."
|
||||||
|
cmdarg_info "author" "Some Poor Bastard <somepoorbastard@hell.com>"
|
||||||
|
cmdarg_info "copyright" "(C) 2013"
|
||||||
|
|
||||||
|
cmdarg_parse
|
||||||
|
============
|
||||||
|
|
||||||
|
This command does what you expect, parsing your command line arguments. However you must pass your command line arguments to it. Generally this means:
|
||||||
|
|
||||||
|
cmdarg_parse "$@"
|
||||||
|
|
||||||
|
... Beware that "$@" will change depending on your context. So if you have a main() function called in your script, you need to make sure that you pass "$@" from the toplevel script in to it, otherwise the options will be blank when you pass them to cmdarg_parse.
|
||||||
|
|
||||||
|
Any argument parsed that has a validator assigned, and whose validator returns nonzero, is considered a failure. Any REQUIRED argument that is not specified is considered a failure.
|
||||||
|
|
||||||
|
For every argument, a global associative array "cmdarg_cfg" is populated with the long version of the option. E.g., in the example above, '-c' would become ${cmdarg_cfg['groupmap']}, for friendlier access during scripting.
|
||||||
|
|
||||||
|
I love it when a plan comes together
|
||||||
|
====================================
|
||||||
|
|
||||||
|
Given some code like this:
|
||||||
|
|
||||||
|
cmdarg_info "header" "Convert existing old LDAP users to the new LDAP server/schema."
|
||||||
|
cmdarg_info "author" "Some Poor Bastard <somepoorbastard@hell.com>"
|
||||||
|
cmdarg_info "copyright" "(C) 2013"
|
||||||
|
|
||||||
|
cmdarg 'C:' 'cfgfile' 'Config file that contains options that should be used in place of command line args' '' 'test -e $OPTARG'
|
||||||
|
cmdarg 'c:' 'groupmap' 'A CSV file mapping usernames to groups that they should belong to post-conversion' '' 'test -e $OPTARG'
|
||||||
|
cmdarg 'l:' 'source_ldap' 'Source (old) LDAP URI'
|
||||||
|
cmdarg 'u:' 'source_ldap_username' 'Source (old) LDAP Username'
|
||||||
|
cmdarg 'p:' 'source_ldap_password' 'Source (old) LDAP Password'
|
||||||
|
cmdarg 'b:' 'source_ldap_basedn' 'Source (old) LDAP Base DN (ou=x,dc=x,dc=x)'
|
||||||
|
cmdarg 'o:' 'source_ldap_ou_users' 'Source (old) LDAP ou for Users' 'users'
|
||||||
|
cmdarg 'g:' 'source_ldap_ou_groups' 'Source (old) LDAP ou for Groups' 'groups'
|
||||||
|
cmdarg 'L:' 'dest_ldap' 'Destination (new) LDAP URI'
|
||||||
|
cmdarg 'U:' 'dest_ldap_username' 'Destination (new) LDAP Username'
|
||||||
|
cmdarg 'P:' 'dest_ldap_password' 'Destination (new) LDAP Password'
|
||||||
|
cmdarg 'B:' 'dest_ldap_basedn' 'Destination (new) LDAP Base DN (dc=x,dc=x)'
|
||||||
|
cmdarg 'O:' 'source_ldap_ou_users' 'Destination (new) LDAP ou for Users' 'users'
|
||||||
|
cmdarg 'G:' 'source_ldap_ou_groups' 'Destination (new) LDAP ou for Groups' 'groups'
|
||||||
|
cmdarg 's:' 'slappasswd_salt' 'Slappasswd salt format (man slappasswd)' 'rofflewaffles%s'
|
||||||
|
cmdarg 'S:' 'slappasswd_scheme' 'Slappasswwd hash scheme to use (CRYPT|MD5|SMD5|SSHA|SHA)' 'SSHA' 'echo $OPTARG | grep -E "CRYPT|MD5|SMD5|SSHA|SHA" >/dev/null 2>&1'
|
||||||
|
|
||||||
|
cmdarg_parse "$@"
|
||||||
|
|
||||||
|
... Here's what we can expect to see from the usage message:
|
||||||
|
|
||||||
|
$ ./ldap-convert.sh -h
|
||||||
|
ldap-convert.sh (C) 2013 : Some Poor Bastard <somepoorbastard@hell.com>
|
||||||
|
|
||||||
|
Convert existing LDAP users to the new LDAP server/schema.
|
||||||
|
|
||||||
|
Required Arguments:
|
||||||
|
-C : Config file that contains options that should be used in place of command line args
|
||||||
|
-c : A CSV file mapping usernames to groups that they should belong to post-conversion
|
||||||
|
-l : Source (old) LDAP URI
|
||||||
|
-u : Source (old) LDAP Username
|
||||||
|
-p : Source (old) LDAP Password
|
||||||
|
-b : Source (old) LDAP Base DN (ou=x,dc=x,dc=x)
|
||||||
|
-L : Destination (new) LDAP URI
|
||||||
|
-U : Destination (new) LDAP Username
|
||||||
|
-P : Destination (new) LDAP Password
|
||||||
|
-B : Destination (new) LDAP Base DN (dc=x,dc=x)
|
||||||
|
|
||||||
|
Optional Arguments:
|
||||||
|
-o : Source (old) LDAP ou for Users (Default "users")
|
||||||
|
-g : Source (old) LDAP ou for Groups (Default "groups")
|
||||||
|
-O : Destination (new) LDAP ou for Users (Default "users")
|
||||||
|
-G : Destination (new) LDAP ou for Groups (Default "groups")
|
||||||
|
-s : Slappasswd salt format (man slappasswd) (Default "rofflewaffles%s")
|
||||||
|
-S : Slappasswwd hash scheme to use (CRYPT|MD5|SMD5|SSHA|SHA) (Default "SSHA")
|
||||||
|
|
||||||
|
... And if we run it without '-h', then the argument parser (rather helpfully) tells us which arguments we've failed to specify, before printing the help:
|
||||||
|
|
||||||
|
$ ./ldap-convert.sh
|
||||||
|
Invalid value for -c :
|
||||||
|
Invalid value for -C :
|
||||||
|
Missing arguments : -C -c -l -u -p -b -L -U -P -B
|
||||||
|
|
||||||
|
ldap-convert.sh (C) 2013 : Some Poor Bastard <somepoorbastard@hell.com>
|
||||||
|
|
||||||
|
Convert existing LDAP users to the new LDAP server/schema.
|
||||||
|
|
||||||
|
Required Arguments:
|
||||||
|
-C : Config file that contains options that should be used in place of command line args
|
||||||
|
-c : A CSV file mapping usernames to groups that they should belong to post-conversion
|
||||||
|
-l : Source (old) LDAP URI
|
||||||
|
-u : Source (old) LDAP Username
|
||||||
|
-p : Source (old) LDAP Password
|
||||||
|
-b : Source (old) LDAP Base DN (ou=x,dc=x,dc=x)
|
||||||
|
-L : Destination (new) LDAP URI
|
||||||
|
-U : Destination (new) LDAP Username
|
||||||
|
-P : Destination (new) LDAP Password
|
||||||
|
-B : Destination (new) LDAP Base DN (dc=x,dc=x)
|
||||||
|
|
||||||
|
Optional Arguments:
|
||||||
|
-o : Source (old) LDAP ou for Users (Default "users")
|
||||||
|
-g : Source (old) LDAP ou for Groups (Default "groups")
|
||||||
|
-O : Destination (new) LDAP ou for Users (Default "users")
|
||||||
|
-G : Destination (new) LDAP ou for Groups (Default "groups")
|
||||||
|
-s : Slappasswd salt format (man slappasswd) (Default "rofflewaffles%s")
|
||||||
|
-S : Slappasswwd hash scheme to use (CRYPT|MD5|SMD5|SSHA|SHA) (Default "SSHA")
|
||||||
|
|
||||||
|
... And here's what the cmdarg_cfg associate array winds up holding, illustrated with some debug prints:
|
||||||
|
|
||||||
|
$ ./ldap-convert.sh -c ./users_groups_map.csv -l 1 -u 1 -p 1 -b 1 -L 1 -U 1 -P 1 -B 1
|
||||||
|
|
||||||
|
cmdarg_cfg[groupmap]="./users_groups_map.csv"
|
||||||
|
cmdarg_cfg[slappasswd_salt]="rofflewaffles%s"
|
||||||
|
cmdarg_cfg[source_ldap_ou_groups]="groups"
|
||||||
|
cmdarg_cfg[slappasswd_scheme]="SSHA"
|
||||||
|
cmdarg_cfg[dest_ldap_username]="1"
|
||||||
|
cmdarg_cfg[dest_ldap_password]="1"
|
||||||
|
cmdarg_cfg[source_ldap_password]="1"
|
||||||
|
cmdarg_cfg[source_ldap_username]="1"
|
||||||
|
cmdarg_cfg[cfgfile]="/dev/null"
|
||||||
|
cmdarg_cfg[dest_ldap_basedn]="1"
|
||||||
|
cmdarg_cfg[source_ldap_basedn]="1"
|
||||||
|
cmdarg_cfg[source_ldap_ou_users]="users"
|
||||||
|
cmdarg_cfg[source_ldap]="1"
|
||||||
|
cmdarg_cfg[dest_ldap]="1"
|
||||||
180
cmdarg.sh
Normal file
180
cmdarg.sh
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
CMDARG_FLAG_WITHARG=1
|
||||||
|
|
||||||
|
function cmdarg
|
||||||
|
{
|
||||||
|
# cmdarg <option> <key> <description> [default value] [validator function]
|
||||||
|
#
|
||||||
|
# option : The short name (single letter) of the option
|
||||||
|
# key : The long key that should be placed into cmdarg_cfg[] for this option
|
||||||
|
# description : The text description for this option to be used in cmdarg_usage
|
||||||
|
#
|
||||||
|
# default value : The default value, if any, for the argument
|
||||||
|
# validator : This is passed through eval(), with $OPTARG equal to the current
|
||||||
|
# value of the argument in question, and must return non-zero if
|
||||||
|
# the argument value is invalid. Can be straight bash, but it really
|
||||||
|
# should be the name of a function. This may be enforced in future versions
|
||||||
|
# of the library.
|
||||||
|
set -u
|
||||||
|
shortopt=${1:0:1}
|
||||||
|
if [[ "${1:1:2}" == ":" ]]; then
|
||||||
|
CMDARG_FLAGS[$shortopt]=$CMDARG_FLAG_WITHARG
|
||||||
|
else
|
||||||
|
CMDARG_FLAGS[$shortopt]=0
|
||||||
|
fi
|
||||||
|
CMDARG["$shortopt"]=$2
|
||||||
|
CMDARG_REV["$2"]=$shortopt
|
||||||
|
CMDARG_DESC["$shortopt"]=$3
|
||||||
|
CMDARG_DEFAULT["$shortopt"]=${4:-}
|
||||||
|
if [[ ${CMDARG_FLAGS[$shortopt]} -eq $CMDARG_FLAG_WITHARG ]] && [[ "${4:-}" == "" ]]; then
|
||||||
|
CMDARG_REQUIRED+=($shortopt)
|
||||||
|
else
|
||||||
|
CMDARG_OPTIONAL+=($shortopt)
|
||||||
|
fi
|
||||||
|
cmdarg_cfg["$2"]="${4:-}"
|
||||||
|
CMDARG_VALIDATORS["$shortopt"]="${5:-}"
|
||||||
|
CMDARG_GETOPTLIST="${CMDARG_GETOPTLIST}$1"
|
||||||
|
set +u
|
||||||
|
}
|
||||||
|
|
||||||
|
function cmdarg_info
|
||||||
|
{
|
||||||
|
# cmdarg <flag> <value>
|
||||||
|
#
|
||||||
|
# Sets various flags about your script that are printed during cmdarg_usage
|
||||||
|
#
|
||||||
|
FLAGS="header|copyright|footer|author"
|
||||||
|
echo "$1" | grep -E "$FLAGS" >/dev/null 2>&1
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "cmdarg_info <flag> <value>" >&2
|
||||||
|
echo "Where <flag> is one of $FLAGS" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
CMDARG_INFO["$1"]=$2
|
||||||
|
}
|
||||||
|
|
||||||
|
function cmdarg_usage
|
||||||
|
{
|
||||||
|
# cmdarg_usage
|
||||||
|
#
|
||||||
|
# Prints a very helpful usage message about the current program.
|
||||||
|
echo "$(basename $0) ${CMDARG_INFO['copyright']} : ${CMDARG_INFO['author']}"
|
||||||
|
echo
|
||||||
|
echo "${CMDARG_INFO['header']}"
|
||||||
|
echo
|
||||||
|
local key
|
||||||
|
if [[ "${!CMDARG_REQUIRED[@]}" != "" ]]; then
|
||||||
|
echo "Required Arguments:"
|
||||||
|
for key in "${CMDARG_REQUIRED[@]}"
|
||||||
|
do
|
||||||
|
local default=""
|
||||||
|
if [ "${CMDARG_DEFAULT[$key]}" != "" ]; then
|
||||||
|
default="(Default \"${CMDARG_DEFAULT[$key]}\")"
|
||||||
|
fi
|
||||||
|
echo " -${key} : ${CMDARG_DESC[$key]} $default"
|
||||||
|
done
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
if [[ "${!CMDARG_OPTIONAL[@]}" != "" ]]; then
|
||||||
|
echo "Optional Arguments:"
|
||||||
|
for key in "${CMDARG_OPTIONAL[@]}"
|
||||||
|
do
|
||||||
|
local default=""
|
||||||
|
if [ "${CMDARG_DEFAULT[$key]}" != "" ]; then
|
||||||
|
default="(Default \"${CMDARG_DEFAULT[$key]}\")"
|
||||||
|
fi
|
||||||
|
echo " -${key} : ${CMDARG_DESC[$key]} $default"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function cmdarg_parse
|
||||||
|
{
|
||||||
|
# cmdarg_parse "$@"
|
||||||
|
#
|
||||||
|
# Call it EXACTLY LIKE THAT, and it will parse your arguments for you.
|
||||||
|
# This function only knows about the arguments that you previously called 'cmdarg' for.
|
||||||
|
local OPTIND
|
||||||
|
local ARGS="$@"
|
||||||
|
|
||||||
|
while getopts "$CMDARG_GETOPTLIST" opt $ARGS; do
|
||||||
|
if [ "$opt" == "h" ]; then
|
||||||
|
cmdarg_usage
|
||||||
|
exit 1
|
||||||
|
elif [ ${CMDARG["${opt}"]+abc} ]; then
|
||||||
|
cmdarg_cfg[${CMDARG[$opt]}]=$OPTARG
|
||||||
|
else
|
||||||
|
cmdarg_usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
OPTARG=""
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- Don't exit early during validation, tell the user
|
||||||
|
# everything they did wrong first
|
||||||
|
failed=0
|
||||||
|
missing=""
|
||||||
|
|
||||||
|
for key in "${CMDARG_REQUIRED[@]}"
|
||||||
|
do
|
||||||
|
if [[ "${cmdarg_cfg[${CMDARG[$key]}]}" == "" ]]; then
|
||||||
|
missing="${missing} -${key}"
|
||||||
|
failed=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
local opt
|
||||||
|
local optarg
|
||||||
|
for opt in "${!cmdarg_cfg[@]}"
|
||||||
|
do
|
||||||
|
shortopt=${CMDARG_REV[$opt]}
|
||||||
|
if [ "${CMDARG_VALIDATORS[$shortopt]}" != "" ]; then
|
||||||
|
OPTARG=${cmdarg_cfg[$opt]}
|
||||||
|
set +e
|
||||||
|
( eval "${CMDARG_VALIDATORS[${shortopt}]}" && [ "$OPTARG" != "" ])
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Invalid value for -$shortopt : ${cmdarg_cfg[$opt]}"
|
||||||
|
failed=1
|
||||||
|
fi
|
||||||
|
set -e
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ $failed -eq 1 ]; then
|
||||||
|
if [[ "$missing" != "" ]]; then
|
||||||
|
echo "Missing arguments : ${missing}"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
cmdarg_usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -z "${cmdarg_cfg[cfgfile]}" ]; then
|
||||||
|
. ${cmdarg_cfg[cfgfile]}
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "${_DEFINED_CMDARG}" == "" ]]; then
|
||||||
|
export _DEFINED_CMDARG=0
|
||||||
|
# Holds the final map of configuration options
|
||||||
|
declare -A cmdarg_cfg
|
||||||
|
# Maps (short arg) -> (long arg)
|
||||||
|
declare -A CMDARG
|
||||||
|
# Maps (long arg) -> (short arg)
|
||||||
|
declare -A CMDARG_REV
|
||||||
|
# A list of optional arguments (e.g., no :)
|
||||||
|
declare -a CMDARG_OPTIONAL
|
||||||
|
# A list of required arguments (e.g., :)
|
||||||
|
declare -a CMDARG_REQUIRED
|
||||||
|
# Maps (short arg) -> (description)
|
||||||
|
declare -A CMDARG_DESC
|
||||||
|
# Maps (short arg) -> default
|
||||||
|
declare -A CMDARG_DEFAULT
|
||||||
|
# Maps (short arg) -> validator
|
||||||
|
declare -A CMDARG_VALIDATORS
|
||||||
|
# Miscellanious info about this script
|
||||||
|
declare -A CMDARG_INFO
|
||||||
|
# Map of (short arg) -> flags
|
||||||
|
declare -A CMDARG_FLAGS
|
||||||
|
CMDARG_GETOPTLIST="h"
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user