123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704 |
- #!/bin/sh
- # Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
- #
- # This Source Code Form is subject to the terms of the Mozilla Public
- # License, v. 2.0. If a copy of the MPL was not distributed with this
- # file, You can obtain one at http://mozilla.org/MPL/2.0/.
- # This is kea-admin script that conducts administrative tasks on the Kea
- # installation. Currently supported operations are:
- #
- # - lease database init
- # - lease database version check
- # - lease database version upgrade
- # Get the location of the kea-admin scripts
- prefix=@prefix@
- SCRIPTS_DIR_DEFAULT=@datarootdir@/@PACKAGE@/scripts
- scripts_dir=${SCRIPTS_DIR_DEFAULT}
- # These are the default parameters. They will likely not work in any
- # specific deployment.
- db_user="keatest"
- db_password="keatest"
- db_name="keatest"
- # lease dump parameters
- dump_type=0
- dump_file=""
- dump_qry=""
- # Include utilities. Use installed version if available and
- # use build version if it isn't.
- if [ -e @datarootdir@/@PACKAGE_NAME@/scripts/admin-utils.sh ]; then
- . @datarootdir@/@PACKAGE_NAME@/scripts/admin-utils.sh
- else
- . @abs_top_srcdir@/src/bin/admin/admin-utils.sh
- fi
- # Prints out usage version.
- usage() {
- printf "kea-admin @PACKAGE_VERSION@\n"
- printf "\n"
- printf "This is a kea-admin script that conducts administrative tasks on\n"
- printf "the Kea installation.\n"
- printf "\n"
- printf "Usage: $0 COMMAND BACKEND [parameters]\n"
- printf "\n"
- printf "COMMAND: Currently supported operations are:\n"
- printf "\n"
- printf " - lease-init: Initalizes new lease database. Useful for first time installation.\n"
- printf " - lease-version: Checks version of the existing lease database scheme. Useful\n"
- printf " - for checking lease DB version when preparing for an upgrade.\n"
- printf " - lease-upgrade: Upgrades your lease database scheme\n"
- printf " - lease-dump: Dump current leases to a CSV file\n"
- printf "\n"
- printf "BACKEND - one of the supported backends: memfile|mysql|pgsql|cql\n"
- printf "\n"
- printf "PARAMETERS: Parameters are optional in general, but may be required\n"
- printf " for specific operation.\n"
- printf " -u or --user name - specifies username when connecting to a database\n"
- printf " -p or --password pass - specifies a password when connecting to a database\n"
- printf " -n or --name database - specifies a database name to connect to\n"
- printf " -d or --directory - path to upgrade scripts (default: ${SCRIPTS_DIR_DEFAULT})\n"
- printf "\n"
- printf " Parameters specific to lease-dump:\n"
- printf " -4 to dump IPv4 leases to file\n"
- printf " -6 to dump IPv6 leases to file\n"
- printf " -o or --output - name of file to which leases will be dumped\n"
- }
- ### Logging functions ###
- # Logs message at the error level.
- # Takes one parameter that is printed as is.
- log_error() {
- printf "ERROR/kea-admin: ${1}\n"
- }
- # Logs message at the warning level.
- # Takes one parameter that is printed as is.
- log_warning() {
- printf "WARNING/kea-admin: ${1}\n"
- }
- # Logs message at the info level.
- # Takes one parameter that is printed as is.
- log_info() {
- printf "INFO/kea-admin: ${1}\n"
- }
- ### Convenience functions ###
- # Checks if the value is in the list. An example usage of this function
- # is to determine whether the kea-admin command belongs to the list of
- # supported commands.
- is_in_list() {
- local member=${1} # Value to be checked
- local list="${2}" # Comma separated list of items
- _inlist=0 # Return value: 0 if not in list, 1 otherwise.
- if [ -z ${member} ]; then
- log_error "missing ${class}"
- fi
- # Iterate over all items on the list and compare with the member.
- # If they match, return, otherwise log error and exit.
- for item in ${list}
- do
- if [ ${item} = ${member} ]; then
- _inlist=1
- return
- fi
- done
- }
- ### Functions that implement database initialization commands
- memfile_init() {
- # @todo Implement this as part of #3601
- log_error "NOT IMPLEMENTED"
- exit 1
- }
- # Initializes a new, empty MySQL database.
- # It essentially calls scripts/mysql/dhcpdb_create.mysql script, with
- # some extra sanity checks. It will refuse to use it if there are any
- # existing tables. It's better safe than sorry.
- mysql_init() {
- printf "Checking if there is a database initialized already. Please ignore errors.\n"
- # Let's try to count the number of tables. Anything above 0 means that there
- # is some database in place. If there is anything, we abort. Note that
- # mysql may spit out connection or access errors to stderr, we ignore those.
- # We should not hide them as they may give hints to user what is wrong with
- # his setup.
- #
- RESULT=`mysql_execute "SHOW TABLES;"`
- ERRCODE=$?
- if [ $ERRCODE -ne 0 ]
- then
- log_error "mysql_init table query failed, mysql status = $ERRCODE"
- exit 1
- fi
- COUNT=`echo $RESULT | wc -w`
- if [ $COUNT -gt 0 ]; then
- # Let't start with a new line. mysql could have printed something out.
- printf "\n"
- log_error "Expected empty database $db_name, but there are $COUNT tables: \n$RESULT. Aborting."
- exit 1
- fi
- printf "Initializing database using script %s\n" $scripts_dir/mysql/dhcpdb_create.mysql
- mysql -B --user=$db_user --password=$db_password $db_name < $scripts_dir/mysql/dhcpdb_create.mysql
- ERRCODE=$?
- printf "mysql returned status code $ERRCODE\n"
- if [ "$ERRCODE" -eq 0 ]; then
- printf "Lease DB version reported after initialization: "
- mysql_version
- printf "\n"
- fi
- exit $ERRCODE
- }
- pgsql_init() {
- printf "Checking if there is a database initialized already. Please ignore errors.\n"
- # Let's try to count the number of tables. Anything above 0 means that there
- # is some database in place. If there is anything, we abort.
- RESULT=`pgsql_execute "\d"`
- ERRCODE=$?
- if [ "$ERRCODE" -ne 0 ]; then
- log_error "pgsql_init: table query failed, status code: $ERRCODE?"
- exit 1
- fi
- COUNT=`echo "$RESULT" | wc -w`
- if [ $COUNT -gt 0 ]; then
- printf "\n"
- log_error "Expected empty database $db_name, but the following tables are present \n$RESULT. Aborting."
- exit 2
- fi
- init_script="$scripts_dir/pgsql/dhcpdb_create.pgsql"
- printf "Initializing database using script %s\n" $init_script
- RESULT=`pgsql_execute_script $init_script`
- ERRCODE=$?
- if [ "$ERRCODE" -ne 0 ]; then
- log_error "Database initialization failed, status code: $ERRCODE?"
- exit 1
- fi
- version=`pgsql_version`
- printf "Lease DB version reported after initialization: $version\n"
- exit 0
- }
- cql_init() {
- printf "Checking if there is a database initialized already... Please ignore errors.\n"
- result=`cql_execute "USE $db_name; DESCRIBE tables;"`
- if [ "$result"="<empty>" ]; then
- printf "Creating and initializing tables using script %s...\n" $scripts_dir/cql/dhcpdb_create.cql
- cql_execute_script $scripts_dir/cql/dhcpdb_create.cql
- else
- log_error "Expected empty database $db_name, but the following tables are present \n$result. Aborting."
- exit 2
- fi
- version=`cql_version`
- printf "Lease DB version reported after initialization: $version\n"
- exit 0
- }
- ### Functions that implement database version checking commands
- memfile_version() {
- # @todo Implement this as part of #3601
- log_error "NOT IMPLEMENTED"
- exit 1
- }
- ### Functions used for upgrade
- memfile_upgrade() {
- # @todo Implement this as part of #3601
- log_error "NOT IMPLEMENTED"
- exit 1
- }
- # Upgrades existing MySQL database installation. The idea is that
- # it will go over all upgrade scripts from (prefix)/share/kea/scripts/mysql
- # and run them one by one. They will be named properly, so they will
- # be run in order.
- #
- # This function prints version before and after upgrade.
- mysql_upgrade() {
- printf "Lease DB version reported before upgrade: "
- mysql_version
- printf "\n"
- # Check if the scripts directory exists at all.
- if [ ! -d ${scripts_dir}/mysql ]; then
- log_error "Invalid scripts directory: ${scripts_dir}/mysql"
- exit 1
- fi
- # Check if there are any files in it
- num_files=$(find ${scripts_dir}/mysql/upgrade*.sh -type f | wc -l)
- if [ $num_files -eq 0 ]; then
- log_error "No scripts in ${scripts_dir}/mysql or the directory is not readable or does not have any upgrade* scripts."
- exit 1
- fi
- for script in ${scripts_dir}/mysql/upgrade*.sh
- do
- echo "Processing $script file..."
- sh ${script} --user=${db_user} --password=${db_password} ${db_name}
- done
- printf "Lease DB version reported after upgrade: "
- mysql_version
- printf "\n"
- }
- pgsql_upgrade() {
- version=`pgsql_version`
- printf "Lease DB version reported before upgrade: $version\n"
- # Check if the scripts directory exists at all.
- if [ ! -d ${scripts_dir}/pgsql ]; then
- log_error "Invalid scripts directory: ${scripts_dir}/pgsql"
- exit 1
- fi
- # Check if there are any files in it
- num_files=$(find ${scripts_dir}/pgsql/upgrade*.sh -type f | wc -l)
- if [ $num_files -eq 0 ]; then
- log_error "No scripts in ${scripts_dir}/pgsql or the directory is not readable or does not have any upgrade* scripts."
- exit 1
- fi
- # Postgres psql does not accept pw on command line, but can do it
- # thru an env
- export PGPASSWORD=$db_password
- for script in ${scripts_dir}/pgsql/upgrade*.sh
- do
- echo "Processing $script file..."
- sh ${script} -U ${db_user} -d ${db_name}
- done
- version=`pgsql_version`
- printf "Lease DB version reported after upgrade: $version\n"
- exit 0
- }
- cql_upgrade() {
- version=`cql_version`
- printf "Lease DB version reported before upgrade: $version\n"
- # Check if the scripts directory exists at all.
- if [ ! -d ${scripts_dir}/cql ]; then
- log_error "Invalid scripts directory: ${scripts_dir}/cql"
- exit 1
- fi
- # Check if directory is readable.
- if [ ! -r ${scripts_dir}/cql ]; then
- log_error "Directory is not readable: ${scripts_dir}/cql"
- exit 1
- fi
- # Check if there are upgrade scripts.
- files=$(find ${scripts_dir}/cql/upgrade*.sh -type f)
- if [ $? -eq 0 ]; then # Upgrade scripts are present.
- for script in ${scripts_dir}/cql/upgrade*.sh
- do
- echo "Processing $script file..."
- sh ${script} -u ${db_user} -p ${db_password} -k ${db_name}
- done
- else
- echo "No upgrade script available."
- fi
- version=`cql_version`
- printf "Lease DB version reported after upgrade: $version\n"
- exit 0
- }
- # Utility function which tests if the given file exists and
- # if so notifies the user and provides them the opportunity
- # to abort the current command.
- check_file_overwrite () {
- local file=$1
- if [ -e ${file} ]
- then
- echo "Output file, $file, exists and will be overwritten."
- echo "Do you wish to continue? (y/n)"
- read ans
- if [ ${ans} != "y" ]
- then
- echo "$command aborted by user."
- exit 1
- fi
- fi
- }
- ### Functions used for dump
- # Sets the global variable, dump_qry, to the schema-version specific
- # SQL text needed to dump the lease data for the current backend
- # and protocol
- get_dump_query() {
- local version=$1
- case ${backend} in
- mysql)
- invoke="call"
- ;;
- pgsql)
- invoke="select * from"
- ;;
- cql)
- invoke="select * from"
- ;;
- *)
- log_error "unsupported backend ${backend}"
- usage
- exit 1
- ;;
- esac
- dump_qry="${invoke} lease${dump_type}DumpHeader();${invoke} lease${dump_type}DumpData();";
- }
- memfile_dump() {
- log_error "lease-dump is not supported for memfile"
- exit 1
- }
- mysql_dump() {
- # get the correct dump query
- version=`mysql_version`
- retcode=$?
- if [ $retcode -ne 0 ]
- then
- log_error "lease-dump: mysql_version failed, exit code $retcode"
- exit 1;
- fi
- # Fetch the correct SQL text. Note this function will exit
- # if it fails.
- get_dump_query $version
- # Make sure they specified a file
- if [ "$dump_file" = "" ]; then
- log_error "you must specify an output file for lease-dump"
- usage
- exit 1
- fi
- # If output file exists, notify user, allow them a chance to bail
- check_file_overwrite $dump_file
- # Check the temp file too
- tmp_file="$dump_file.tmp"
- check_file_overwrite $tmp_file
- # Run the sql to output tab-delimited lease data to a temp file.
- # By using a temp file we can check for MySQL errors before using
- # 'tr' to translate tabs to commas. We do not use MySQL's output
- # to file as that requires linux superuser privileges to execute
- # the select.
- mysql_execute "${dump_qry}" > $tmp_file
- retcode=$?
- if [ $retcode -ne 0 ]; then
- log_error "lease-dump: mysql_execute failed, exit code $retcode";
- exit 1
- fi
- # Now translate tabs to commas.
- cat $tmp_file | tr '\t' ',' >$dump_file
- if [ $? -ne 0 ]; then
- log_error "lease-dump: reformatting failed";
- exit 1
- fi
- # delete the tmp file on success
- rm $tmp_file
- echo lease$dump_type successfully dumped to $dump_file
- exit 0
- }
- ### Functions used for dump
- pgsql_dump() {
- version=`pgsql_version`
- get_dump_query $version
- # Make sure they specified a file
- if [ "$dump_file" = "" ]; then
- log_error "you must specify an output file for lease-dump"
- usage
- exit 1
- fi
- # If output file exists, notify user, allow them a chance to bail
- check_file_overwrite $dump_file
- # psql does not accept password as a parameter but will look in the environment
- export PGPASSWORD=$db_password
- # Call psql and redirect output to the dump file. We don't use psql "to csv"
- # as it can only be run as db superuser.
- echo "$dump_qry" | psql --set ON_ERROR_STOP=1 -t -q --user=$db_user --dbname=$db_name -w --no-align --field-separator=',' >$dump_file
- retcode=$?
- # Check for errors.
- if [ $retcode -ne 0 ]; then
- log_error "lease-dump: psql call failed, exit code: $retcode";
- exit 1
- fi
- echo lease$dump_type successfully dumped to $dump_file
- exit 0
- }
- cql_dump() {
- # get the correct dump query
- version=`cql_version`
- retcode=$?
- if [ $retcode -ne 0 ]
- then
- log_error "lease-dump: cql_version failed, exit code $retcode"
- exit 1;
- fi
- # Fetch the correct SQL text. Note this function will exit
- # if it fails.
- select_where_clause=""
- if [ $dump_type -eq 4 ]; then
- dump_qry="SELECT address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state FROM keatest.lease4"
- select_where_clause=" WHERE address = 0" # invalid address
- elif [ $dump_type -eq 6 ]; then
- dump_qry="SELECT address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,hwtype,hwaddr_source,state FROM keatest.lease6"
- select_where_clause=" WHERE address = ::" # invalid address
- fi
- # Make sure they specified a file
- if [ "$dump_file" = "" ]; then
- log_error "you must specify an output file for lease-dump"
- usage
- exit 1
- fi
- # If output file exists, notify user, allow them a chance to bail
- check_file_overwrite $dump_file
- cql_execute "${dump_qry}${select_where_clause}" | head -n 2 | tail -n 1 | sed -e 's/\s*//g' | sed -e 's/|/,/g' > $dump_file
- if [ $? -ne 0 ]; then
- log_error "lease-dump: cql_execute failed, exit code $retcode";
- exit 1
- fi
- cql_execute "${dump_qry}" | tail -n +4 | head -n -2 | sed -e 's/\s*//g' | sed -e 's/|/,/g' | sort -r >> $dump_file
- if [ $? -ne 0 ]; then
- log_error "lease-dump: cql_execute failed, exit code $retcode";
- exit 1
- fi
- echo lease$dump_type successfully dumped to $dump_file
- exit 0
- }
- ### Script starts here ###
- # First, find what the command is
- command=${1}
- if [ -z ${command} ]; then
- log_error "missing command"
- usage
- exit 1
- fi
- is_in_list "${command}" "lease-init lease-version lease-upgrade lease-dump"
- if [ ${_inlist} -eq 0 ]; then
- log_error "invalid command: ${command}"
- exit 1
- fi
- shift
- # Second, check what's the backend
- backend=${1}
- if [ -z ${backend} ]; then
- log_error "missing backend"
- usage
- exit 1
- fi
- is_in_list "${backend}" "memfile mysql pgsql cql"
- if [ ${_inlist} -eq 0 ]; then
- log_error "invalid backend: ${backend}"
- exit 1
- fi
- shift
- # Ok, let's process parameters (if there are any)
- while [ ! -z "${1}" ]
- do
- option=${1}
- case ${option} in
- # Specify database user
- -u|--user)
- shift
- db_user=${1}
- if [ -z ${db_user} ]; then
- log_error "-u or --user requires a parameter"
- usage
- exit 1
- fi
- ;;
- # Specify database password
- -p|--password)
- shift
- db_password=${1}
- if [ -z ${db_password} ]; then
- log_error "-p or --password requires a parameter"
- usage
- exit 1
- fi
- ;;
- # Specify database name
- -n|--name)
- shift
- db_name=${1}
- if [ -z ${db_name} ]; then
- log_error "-n or --name requires a parameter"
- usage
- exit 1
- fi
- ;;
- -d|--directory)
- shift
- scripts_dir=${1}
- if [ -z ${scripts_dir} ]; then
- log_error "-d or --directory requires a parameter"
- usage
- exit 1
- fi
- ;;
- # specify DHCPv4 lease type
- -4)
- if [ $dump_type -eq 6 ]; then
- log_error "you may not specify both -4 and -6"
- usage
- exit 1
- fi
- dump_type=4
- ;;
- # specify DHCPv6 lease type
- -6)
- if [ $dump_type -eq 4 ]; then
- log_error "you may not specify both -4 and -6"
- usage
- exit 1
- fi
- dump_type=6
- ;;
- # specify output file, currently only used by lease dump
- -o|--output)
- shift
- dump_file=${1}
- if [ -z ${dump_file} ]; then
- log_error "-o or --output requires a parameter"
- usage
- exit 1
- fi
- ;;
- *)
- log_error "invalid option: ${option}"
- usage
- exit 1
- esac
- shift
- done
- case ${command} in
- # Initialize the database
- lease-init)
- case ${backend} in
- memfile)
- memfile_init
- ;;
- mysql)
- mysql_init
- ;;
- pgsql)
- pgsql_init
- ;;
- cql)
- cql_init
- ;;
- esac
- ;;
- lease-version)
- case ${backend} in
- memfile)
- memfile_version
- ;;
- mysql)
- mysql_version
- printf "\n"
- ;;
- pgsql)
- pgsql_version
- ;;
- cql)
- cql_version
- ;;
- esac
- ;;
- lease-upgrade)
- case ${backend} in
- memfile)
- memfile_upgrade
- ;;
- mysql)
- mysql_upgrade
- ;;
- pgsql)
- pgsql_upgrade
- ;;
- cql)
- cql_upgrade
- ;;
- esac
- ;;
- lease-dump)
- case ${backend} in
- memfile)
- memfile_dump
- ;;
- mysql)
- mysql_dump
- ;;
- pgsql)
- pgsql_dump
- ;;
- cql)
- cql_dump
- ;;
- esac
- ;;
- esac
- exit 0
|