diff --git a/.gitignore b/.gitignore index 9a0a5f6600c9..f852e52215e8 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,9 @@ core.* *.gcno *.gcda +*.deb +*.rpm + .DS_Store *.swp *.diff @@ -110,3 +113,6 @@ data-* cluster-init datafile-*.db +# by build process +arangodb-linux-amd64 +last_compiled_version.sha diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c0d037d2939..21c69a13afa6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -282,9 +282,23 @@ get_filename_component(PYTHON_EXECUTABLE "${PYTHON_EXECUTABLE}" REALPATH) set($ENV{PYTHON_EXECUTABLE} ${PYTHON_EXECUTABLE}) +# FIXME the build containers seem to have a +# /usr/bin/ch(mod|own) to prevent the search +# to find those files the NO_DEFAULT_PATH +# argument is passed if (NOT WINDOWS) - find_program(CHMOD_EXECUTABLE chmod) - find_program(CHOWN_EXECUTABLE chown) + find_program( + CHMOD_EXECUTABLE chmod + PATHS "/bin/" "/usr/bin/" + NO_DEFAULT_PATH + ) + message(STATUS "chmod found in ${CHMOD_EXECUTABLE}") + find_program( + CHOWN_EXECUTABLE chown + PATHS "/bin" "/usr/bin" + NO_DEFAULT_PATH + ) + message(STATUS "chown found in ${CHOWN_EXECUTABLE}") endif() ################################################################################ @@ -894,6 +908,33 @@ if (USE_MAINTAINER_MODE) endforeach () add_custom_target(errorfiles ALL DEPENDS ${ERROR_FILES_GEN}) + + set(EXIT_CODE_FILES + lib/Basics/exitcodes.h + lib/Basics/exitcodes.cpp + js/common/bootstrap/exitcodes.js + Installation/Windows/Plugins/exitcodes.nsh + ) + + set(EXIT_CODE_FILES_GEN) + set(EXIT_CODES_DAT lib/Basics/exitcodes.dat) + + foreach (m IN LISTS EXIT_CODE_FILES) + add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/${m} + COMMAND ${PYTHON_EXECUTABLE} ./utils/generateExitCodesFiles.py ./${EXIT_CODES_DAT} ./${m}.tmp + COMMAND ${CMAKE_COMMAND} -E copy_if_different ./${m}.tmp ./${m} + COMMAND ${CMAKE_COMMAND} -E remove ./${m}.tmp + DEPENDS ${CMAKE_SOURCE_DIR}/${EXIT_CODES_DAT} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMENT "Building exitcode files ${m}" + VERBATIM + ) + + list(APPEND EXIT_CODE_FILES_GEN ${CMAKE_SOURCE_DIR}/${m}) + endforeach () + + add_custom_target(exitcodefiles ALL DEPENDS ${EXIT_CODE_FILES_GEN}) endif () ################################################################################ diff --git a/Installation/Jenkins/build.sh b/Installation/Jenkins/build.sh index c071ff1dcaf6..b936d9b108ee 100755 --- a/Installation/Jenkins/build.sh +++ b/Installation/Jenkins/build.sh @@ -656,10 +656,18 @@ if test "${DOWNLOAD_STARTER}" == 1; then if test -f "${TN}"; then rm -f "${TN}" fi - curl -LO "${STARTER_URL}" FN=$(echo "${STARTER_URL}" |${SED} "s;.*/;;") - mv "${FN}" "${BUILD_DIR}/${TN}" - chmod a+x "${BUILD_DIR}/${TN}" + + echo $FN + if ! test -f "${BUILD_DIR}/${FN}-${STARTER_REV}"; then + curl -LO "${STARTER_URL}" + cp "${FN}" "${BUILD_DIR}/${TN}" + touch "${BUILD_DIR}/${FN}-${STARTER_REV}" + chmod a+x "${BUILD_DIR}/${TN}" + echo "downloaded ${BUILD_DIR}/${FN}-${STARTER_REV} MD5: $(${MD5} < "${BUILD_DIR}/${TN}")" + else + echo "using already downloaded ${BUILD_DIR}/${FN}-${STARTER_REV} MD5: $(${MD5} < "${BUILD_DIR}/${TN}")" + fi fi CONFIGURE_OPTIONS+=("-DTHIRDPARTY_BIN=${BUILD_DIR}/${TN}") fi diff --git a/Installation/Windows/Plugins/exitcodes.nsh b/Installation/Windows/Plugins/exitcodes.nsh new file mode 100644 index 000000000000..526cbf3567e9 --- /dev/null +++ b/Installation/Windows/Plugins/exitcodes.nsh @@ -0,0 +1,75 @@ + +!include "LogicLib.nsh" +!macro printExitCode exitCode Message + Push "${exitCode}" + Push "${Message}" + Call printExitCode +!macroend +Function printExitCode +pop $1 +pop $2 +${Switch} $0 + + + ${Case} 0 # EXIT_SUCCESS + MessageBox MB_ICONEXCLAMATION '$1:$\r$\nsuccess' + ; No error has occurred. + ${Break} + + ${Case} 1 # EXIT_FAILED + MessageBox MB_ICONEXCLAMATION '$1:$\r$\nexit with error' + ; Will be returned when a general error occurred. + ${Break} + + ${Case} 2 # EXIT_CODE_RESOLVING_FAILED + MessageBox MB_ICONEXCLAMATION '$1:$\r$\nexit code resolving failed' + ; fill me + ${Break} + + ${Case} 5 # EXIT_BINARY_NOT_FOUND + MessageBox MB_ICONEXCLAMATION '$1:$\r$\nbinary not found' + ; fill me + ${Break} + + ${Case} 6 # EXIT_CONFIG_NOT_FOUND + MessageBox MB_ICONEXCLAMATION '$1:$\r$\nconfig not found' + ; fill me + ${Break} + + ${Case} 10 # EXIT_UPGRADE_FAILED + MessageBox MB_ICONEXCLAMATION '$1:$\r$\nupgrade failed' + ; Will be returned when the database upgrade failed + ${Break} + + ${Case} 11 # EXIT_UPGRADE_REQUIRED + MessageBox MB_ICONEXCLAMATION '$1:$\r$\ndb upgrade required' + ; Will be returned when a database upgrade is required + ${Break} + + ${Case} 12 # EXIT_DOWNGRADE_REQUIRED + MessageBox MB_ICONEXCLAMATION '$1:$\r$\ndb downgrade required' + ; Will be returned when a database upgrade is required + ${Break} + + ${Case} 13 # EXIT_VERSION_CHECK_FAILED + MessageBox MB_ICONEXCLAMATION '$1:$\r$\nversion check failed' + ; Will be returned when there is a version mismatch + ${Break} + + ${Case} 20 # EXIT_ALREADY_RUNNING + MessageBox MB_ICONEXCLAMATION '$1:$\r$\nalready running' + ; Will be returned when arangod is already running according to PID-file + ${Break} + + ${Case} 21 # EXIT_COULD_NOT_BIND_PORT + MessageBox MB_ICONEXCLAMATION '$1:$\r$\nport blocked' + ; Will be returned when endpoint is taken by another process + ${Break} + + ${Case} 22 # EXIT_COULD_NOT_LOCK + MessageBox MB_ICONEXCLAMATION '$1:$\r$\ncould not lock - another process could be running' + ; fill me + ${Break} + +${EndSwitch} +FunctionEnd diff --git a/Installation/Windows/Templates/NSIS.template.in b/Installation/Windows/Templates/NSIS.template.in index 0b36b4a5bc61..f69b3d19f76a 100755 --- a/Installation/Windows/Templates/NSIS.template.in +++ b/Installation/Windows/Templates/NSIS.template.in @@ -5,6 +5,7 @@ !addincludedir '@CPACK_PLUGIN_PATH@/UAC-plug-in-NSIS' !addincludedir '@CPACK_PLUGIN_PATH@/' !include "OpenLink.nsh" +!include "exitcodes.nsh" ;-------------------------------- ; Include LogicLib for more readable code @@ -718,7 +719,10 @@ Function UpgradeExisting DetailPrint "Checking whether an existing database needs upgrade: " ExecWait "$INSTDIR\${SBIN_DIR}\arangod.exe --server.rest-server false --log.foreground-tty false --database.check-version" $0 DetailPrint "done Checking whether an existing database needs upgrade: $0" - ${If} $0 == 1 + ${If} $0 != 0 + ${AndIf} $0 != 11 + !insertmacro printExitCode $0 "failed to detect whether we need to Upgrade" + ${ElseIf} $0 == 11 ${AndIf} $AUTOMATIC_UPDATE == "1" DetailPrint "Yes." @@ -740,8 +744,8 @@ Function UpgradeExisting ; Now actually do the upgrade ExecWait "$INSTDIR\${SBIN_DIR}\arangod.exe --server.rest-server false --log.level error --database.auto-upgrade true" $0 DetailPrint "Done running database upgrade: $0" - ${If} $0 == 1 - MessageBox MB_ICONEXCLAMATION "the Upgrade failed, please do a manual upgrade" + ${If} $0 != 0 + !insertmacro printExitCode $0 "the Upgrade failed, please do a manual upgrade" Abort ${EndIf} ${EndIf} @@ -757,6 +761,9 @@ Function SetDBPassword DetailPrint "Done initializing password: $0" ${If} $0 == 0 return + ${Else} + !insertmacro printExitCode $0 "Failed to initialize database password.$\r$\nPlease check the windows event log for more details$\r$\n" + Abort ${EndIf} error: MessageBox MB_OK "Failed to initialize database password.$\r$\nPlease check the windows event log for details." diff --git a/Installation/arangodb-helper b/Installation/arangodb-helper new file mode 100644 index 000000000000..6c54a5d74a0e --- /dev/null +++ b/Installation/arangodb-helper @@ -0,0 +1,146 @@ +#!/bin/sh + +# os detection +ar_detect_os(){ + local file="/etc/centos-release" + local os="unknown release" + if [ -f "$file" ]; then + os="centos" + if grep -q -s " 6" "$file" &>/dev/null ; then + os+="6" + elif grep -q -s " 7" "$file" &>/dev/null ; then + os+="7" + fi + fi + echo "$os" + + #debian + #opensuse + #mac +} +#export detected os +export ARANGO_OS="$(ar_detect_os)" + + +#print error message +ar_err(){ + local msg="$1" + local code="${2-1}" + if ! [ $code -eq 0 ]; then + echo "ERROR: $msg" 1>&2 + fi +} + +#print fatal error message and exit +ar_ferr(){ + local code="${2-1}" + if ! [ $code -eq 0 ]; then + local msg="$1" + echo "FATAL ERROR: $msg" 1>&2 + exit "$code" + fi +} + +## exit codes and other data + +#function for searching .dat files +ar_find_dat_file(){ + local name="$1" + local found=false + for p in "/usr/share/arangodb3" "some other path"; do + local full_path="$p/$name" + if [ -f "$full_path" ]; then + found=true + echo "$full_path" + break + fi + done + + if ! $found; then + echo "$could not find datafile $name" + fi +} + +export ARANGO_ERROR_CODES_DAT="$(ar_find_dat_file exitcodes.dat)" + +ar_exitcode_num_to_string(){ + in="$1" + local file="$ARANGO_ERROR_CODES_DAT" + local found=false + if [ -f "$file" ]; then + while IFS=',' read code num _ ; do + if [ "$in" == "$num" ]; then + echo $code + found=true + break + fi + done < "$file" + else + echo "EXIT_CODE_RESOLVING_FAILED for code $in" + fi + + if ! $found; then + echo "EXIT_CODE_RESOLVING_FAILED for code $in" + fi +} + +ar_exitcode_num_to_message(){ + local in="$1" + if [[ $in == "0" ]]; then + return + fi + local file="$ARANGO_ERROR_CODES_DAT" + local found=false + if [ -f $file ]; then + while IFS=',' read code num message long_message; do + if [ "$in" == "$num" ]; then + echo "$message" + found=true + break + fi + done < "$file" + else + echo "could not resolve exit code $in" + fi + + if ! $found; then + echo "could not resolve exit code $in" + fi +} + +ar_exitcode_string_to_num(){ + local file="$ARANGO_ERROR_CODES_DAT" + local found=false + if [ -f $file ]; then + in="$1" + while IFS=',' read code num _ ; do + if [ "$in" == "$code" ]; then + echo $num + found=true + break + fi + done < "$file" + else + echo 2 + fi + + if ! $found; then + echo 2 + fi +} + +ar_exit_by_num(){ + local code="$1" + local str="$(ar_exitcode_num_to_string $code)" + local msg="$(ar_exitcode_num_to_message $code)" + if [ $code -ne 0 ]; then + echo "FATAL ERROR: $str - $msg" 1>&2 + exit "$code" + fi +} + +ar_exit_by_string(){ + local code=$(ar_exitcode_string_to_num "$1") + ar_exit_by_num $code +} + diff --git a/Installation/arangodb-update-db b/Installation/arangodb-update-db new file mode 100755 index 000000000000..8fcf6bbf393b --- /dev/null +++ b/Installation/arangodb-update-db @@ -0,0 +1,8 @@ +#!/bin/sh + +#update db +/usr/sbin/arangod --uid arangodb --gid arangodb --pid-file /var/run/arangodb3/arangod.pid --server.rest-server false --database.auto-upgrade true + +rv=$? +. /usr/share/arangodb3/arangodb-helper +ar_exit_by_num $rv diff --git a/Installation/debian/config.in b/Installation/debian/config.in index 08e183501859..8592da96fff5 100755 --- a/Installation/debian/config.in +++ b/Installation/debian/config.in @@ -1,81 +1,91 @@ #!/bin/sh set -e +action="$1" +version="$2" + # source debconf stuff . /usr/share/debconf/confmodule db_version 2.0 -db_capb backup +db_capb backup DO_CONFIGURE=no -if test -n "$2"; then -# do we want to reconfigure? - if test "`echo $2 | sed -e 's/[a-zA-Z.-]//g' -e 's;ubuntu;;'`" -lt 127 \ - -o "$1" = reconfigure - then - DO_CONFIGURE=yes +if test -n "$version"; then + # do we want to reconfigure? + short_version="$(echo "$version" | sed -e 's/[a-zA-Z.-]//g' -e 's;ubuntu;;')" + if test "$short_version" -lt 127 -o "$action" = reconfigure; then + DO_CONFIGURE=yes fi -else -# are we in first install? - if test "$1" = "configure"; then - DO_CONFIGURE=yes +else + # are we in first install? + if test "$action" = "configure"; then + DO_CONFIGURE=yes fi fi +#do the actual configure if test "$DO_CONFIGURE" = "yes"; then STATE=1 LASTSTATE=5 - while [ "$STATE" != 0 -a "$STATE" -le "$LASTSTATE" ]; do + while test "$STATE" -ne 0 -a \ + "$STATE" -le "$LASTSTATE" ; do - case "$STATE" in - 1) - db_input high @CPACK_PACKAGE_NAME@/password || true + case "$STATE" in + 1) + db_input high @CPACK_PACKAGE_NAME@/password || true db_go db_get @CPACK_PACKAGE_NAME@/password - #if [ -z "$RET" ]; then - #fi ROOT_PW="$RET" - ;; + ;; 2) - db_input high @CPACK_PACKAGE_NAME@/password_again || true + db_input high @CPACK_PACKAGE_NAME@/password_again || true db_go db_get @CPACK_PACKAGE_NAME@/password_again if [ "$ROOT_PW" = "$RET" ]; then ROOT_PW="" else db_input critical @CPACK_PACKAGE_NAME@/password_mismatch - STATE=$(($STATE - 2)) + STATE=$(($STATE - 2)) db_set @CPACK_PACKAGE_NAME@/password_again "" fi - ;; - 3) + ;; + 3) db_input high @CPACK_PACKAGE_NAME@/upgrade || true - ;; + ;; 4) db_input high @CPACK_PACKAGE_NAME@/storage_engine || true db_go - ;; - 5) + ;; + 5) db_get @CPACK_PACKAGE_NAME@/upgrade - if [ "$RET" = "true" ]; then db_input high @CPACK_PACKAGE_NAME@/backup || true db_go else db_set @CPACK_PACKAGE_NAME@/backup "false" fi - ;; + ;; + + esac + + if db_go; then + STATE=$((STATE + 1)) + else + STATE=$((STATE - 1)) + fi + + done # STATE LOOP +fi # DO_CONFIGURE - esac - if db_go; then - STATE=$(($STATE + 1)) - else - STATE=$(($STATE - 1)) - fi - - done +# test if db-dir is in place but arangod is not installed if +# so try an upgrade +if test -d /var/lib/arangodb3 -a ! -f /usr/sbin/arangod; then + db_set @CPACK_PACKAGE_NAME@/new_install_existing_db_dir "true" +else + db_set @CPACK_PACKAGE_NAME@/new_install_existing_db_dir "false" fi exit 0 diff --git a/Installation/debian/packagedesc.txt b/Installation/debian/packagedesc.txt index 917efb11dd6b..f6e570a8ea2c 100644 --- a/Installation/debian/packagedesc.txt +++ b/Installation/debian/packagedesc.txt @@ -3,7 +3,7 @@ the multi-model NoSQL database graphs, and key-values. Build high performance applications using a convenient SQL-like query language or JavaScript extensions. . - Copyright: 2014-2016 by ArangoDB GmbH + Copyright: 2014-2017 by ArangoDB GmbH Copyright: 2012-2013 by triAGENS GmbH ArangoDB Software www.arangodb.com diff --git a/Installation/debian/postinst.in b/Installation/debian/postinst.in index 71ba7ca9cbff..7f5f9c0fa44a 100755 --- a/Installation/debian/postinst.in +++ b/Installation/debian/postinst.in @@ -1,45 +1,60 @@ #!/bin/sh set -e +action="$1" + ARANGODB="/usr/sbin/arangod" # source debconf library . /usr/share/debconf/confmodule + set +x db_get @CPACK_PACKAGE_NAME@/storage_engine STORAGE_ENGINE=$RET export GLIBCXX_FORCE_NEW=1 + +db_get @CPACK_PACKAGE_NAME@/new_install_existing_db_dir +NEW_INSTALL_EXISTING_DIR=$RET + +#fill in correct storage engine into arangod.conf sed -i /etc/arangodb3/arangod.conf -e "s;storage-engine = auto;storage-engine = $STORAGE_ENGINE;" -if [ "$1" = "configure" -a -z "$2" ]; then + +if test "$action" = "configure" -a \ + -z "$2" -a \ + "$NEW_INSTALL_EXISTING_DIR" = "false" ; then + db_get @CPACK_PACKAGE_NAME@/password + # Escape backslashes and quotes if [ -n "$RET" ]; then - ARANGODB_DEFAULT_ROOT_PASSWORD=`echo "$RET"|sed -e 's;\\\\;\\\\\\\\;g' -e 's;";\\\\";g'` \ - /usr/sbin/arango-init-database \ - --server.rest-server false \ - --server.statistics false --foxx.queues false \ - --uid arangodb --gid arangodb || true + ARANGODB_DEFAULT_ROOT_PASSWORD="$(echo "$RET" | sed -e 's;\\\\;\\\\\\\\;g' -e 's;";\\\\";g')" \ + /usr/sbin/arango-init-database \ + --server.rest-server false \ + --server.statistics false --foxx.queues false \ + --uid arangodb --gid arangodb || true fi + db_set @CPACK_PACKAGE_NAME@/password_again "" db_set @CPACK_PACKAGE_NAME@/password "" db_go fi # check if we should upgrade the database directory - -UPGRADE=false -$ARANGODB --uid arangodb --gid arangodb --server.rest-server false --log.foreground-tty false --database.check-version \ +UPGRADE=false #requires upgrade +$ARANGODB --uid arangodb --gid arangodb \ + --server.rest-server false --log.foreground-tty false + --database.check-version \ || UPGRADE=true -db_get @CPACK_PACKAGE_NAME@/upgrade +db_get @CPACK_PACKAGE_NAME@/upgrade #wants upgrade if [ "$RET" = "true" ]; then if [ "$UPGRADE" = "true" ]; then db_get @CPACK_PACKAGE_NAME@/backup if [ "$RET" = "true" ]; then - BACKUP="/var/lib/arangodb3-`date +%F-%H-%M-%S`" - cp -a /var/lib/arangodb3 $BACKUP + BACKUP="/var/lib/arangodb3-$(date +%F-%H-%M-%S)" + cp -a /var/lib/arangodb3 "$BACKUP" echo "A backup of your database files has been stored in $BACKUP." fi @@ -51,7 +66,7 @@ if [ "$RET" = "true" ]; then elif [ "$UPGRADE" = "true" ]; then echo "Warning: database files need upgrade, automatic upgrade is disable, please do it manually." echo "After you've prepared your system for upgrade run " - echo " /etc/init.d/arangodb3 upgrade" + echo " /usr/share/arangodb3/arangodb-update-db" echo " dpkg --pending --configure" echo "after the packaging system is in stable state again." else diff --git a/Installation/rpm/arangodb.spec.in b/Installation/rpm/arangodb.spec.in index 854e01d3ed84..8fadbad6d72d 100644 --- a/Installation/rpm/arangodb.spec.in +++ b/Installation/rpm/arangodb.spec.in @@ -227,13 +227,13 @@ ArangoDB 3 (https://www.arangodb.com) or JavaScript extensions. First Steps with ArangoDB: - https://www.arangodb.com/quickstart + https://docs.arangodb.com/latest/Manual/GettingStarted/ Upgrading ArangoDB: https://docs.arangodb.com/Installing/Upgrading.html Configuring the storage Engine: - https://docs.arangodb.com/3.2/Manual/Administration/Configuration/GeneralArangod.html#storage-engine + https://docs.arangodb.com/latest/Manual/Administration/Configuration/GeneralArangod.html#storage-engine Upgrading ArangoDB database files: > /etc/init.d/arangodb3 upgrade @@ -262,9 +262,8 @@ export ARANGODB_DEFAULT_ROOT_PASSWORD=`(uname -a ; cat /etc/hostname) | md5sum | echo "SECURITY HINT:" echo "run 'arango-secure-installation' to set a root password" -echo "the current password is $ARANGODB_DEFAULT_ROOT_PASSWORD" -echo "(in case this a FRESH install, for UPGRADE the password" -echo "will not be changed)" +echo "the current password is '$ARANGODB_DEFAULT_ROOT_PASSWORD'" +echo "(You should do this for a FRESH install! For an UPGRADE the password does not need to be changed)" /usr/sbin/arango-init-database --uid arangodb --gid arangodb --server.rest-server false --server.statistics false --foxx.queues false || true diff --git a/Installation/rpm/rc.arangod.Centos b/Installation/rpm/rc.arangod.Centos index 503d19313dbf..00f8b040c76e 100644 --- a/Installation/rpm/rc.arangod.Centos +++ b/Installation/rpm/rc.arangod.Centos @@ -9,13 +9,14 @@ # Source function library. . /etc/rc.d/init.d/functions +. /usr/share/arangodb3/arangodb-helper # Path to the server binary ARANGO_BIN=/usr/sbin/arangod -test -x $ARANGO_BIN || exit 5 +test -x $ARANGO_BIN || ar_exit_by_string EXIT_BINARY_NOT_FOUND ARANGO_SYSCONFIG=/etc/arangodb3/arangod.conf -test -r $ARANGO_SYSCONFIG || exit 6 +test -r $ARANGO_SYSCONFIG || ar_exit_by_string EXIT_CONFIG_NOT_FOUND pidfile=/var/run/arangodb/arangod.pid @@ -25,12 +26,11 @@ start() { echo -n $"Starting $ARANGO_BIN: " PIDDIR=`dirname $pidfile` - [ -d $PIDDIR ] || mkdir $PIDDIR || exit 1 + [ -d $PIDDIR ] || mkdir $PIDDIR || ar_ferr "failed to create $PIDDIR" - ( cd /var/log/arangodb3 && chown -R arangodb:arangodb . && chmod 700 .) || exit 1 - ( cd /var/lib/arangodb3 && chown -R arangodb:arangodb . && chmod 700 .) || exit 1 - ( cd /var/lib/arangodb3-apps && chown -R arangodb:arangodb . && chmod 700 .) || exit 1 - ( cd $PIDDIR && chown arangodb:arangodb . && chmod 700 .) || exit 1 + ( cd /var/lib/arangodb3 && chown -R arangodb:arangodb . && chmod 700 .) || ar_ferr "failed to set permissions on /var/lib/arangodb3" + ( cd /var/lib/arangodb3-apps && chown -R arangodb:arangodb . && chmod 700 .) || ar_ferr "failed to set permissions on /var/lib/arangodb3-apps" + ( cd $PIDDIR && chown arangodb:arangodb . && chmod 700 .) || ar_ferr "failed to set permissions on $PIDDIR" ulimit -H -n 131072 || true ulimit -S -n 131072 || true @@ -58,14 +58,11 @@ start() { if [ "$RETVAL" -eq 0 ]; then $ARANGO_BIN --uid arangodb --gid arangodb --log.foreground-tty false --pid-file "$pidfile" --temp.path "/var/tmp/arangod" --supervisor $@ RETVAL=$? - else - echo "database version check failed, maybe you need to run 'upgrade'?" fi ;; esac - echo - return $RETVAL + ar_exit_by_num ${RETVAL} } @@ -73,12 +70,8 @@ start() { stop() { echo -n $"Stopping $ARANGO_BIN: " killproc -p "${pidfile}" -d 10 $ARANGO_BIN - RETVAL=$? - echo "$RETVAL" - if test "$RETVAL" -ne "0" ; then - exit "$RETVAL" - fi + ar_ferr "could not kill arangod" $RETVAL } @@ -98,7 +91,7 @@ case "$1" in ;; restart) - stop || exit 1 + stop # will exit on fail start ;; @@ -107,7 +100,7 @@ case "$1" in start --upgrade ;; - + reload-log) log_daemon_msg "Re-Opening Logfiles $DESC" "$NAME" diff --git a/Installation/systemd/arangodb3.service.in b/Installation/systemd/arangodb3.service.in index 9ae3a3031de1..008f900c5780 100644 --- a/Installation/systemd/arangodb3.service.in +++ b/Installation/systemd/arangodb3.service.in @@ -17,10 +17,14 @@ Description=ArangoDB database server After=sysinit.target sockets.target timers.target paths.target slices.target network.target syslog.target [Service] -Type=forking +Type=simple LimitNOFILE=131072 PIDFile=/var/run/arangodb3/arangod.pid Environment=GLIBCXX_FORCE_NEW=1 + +# Protect users from making their installation unusable by +# starting arangod with wrong permissions (e.g. as root). +# This will reset the permissions to the working default. ExecStartPre=/usr/bin/install -g arangodb -o arangodb -d /var/tmp/arangodb3 ExecStartPre=/usr/bin/install -g arangodb -o arangodb -d /var/run/arangodb3 ExecStartPre=@CHOWN_EXECUTABLE@ -R arangodb:arangodb /var/log/arangodb3 @@ -29,11 +33,13 @@ ExecStartPre=@CHOWN_EXECUTABLE@ -R arangodb:arangodb /var/lib/arangodb3 ExecStartPre=@CHMOD_EXECUTABLE@ 700 /var/lib/arangodb3 ExecStartPre=@CHOWN_EXECUTABLE@ -R arangodb:arangodb /var/lib/arangodb3-apps ExecStartPre=@CHMOD_EXECUTABLE@ 700 /var/lib/arangodb3-apps -ExecStartPre=/usr/sbin/arangod --uid arangodb --gid arangodb --pid-file /var/run/arangodb3/arangod.pid --server.rest-server false --database.auto-upgrade true -ExecStart=/usr/sbin/arangod --uid arangodb --gid arangodb --pid-file /var/run/arangodb3/arangod.pid --temp.path /var/tmp/arangodb3 --supervisor --log.foreground-tty false + +ExecStart=/usr/sbin/arangod --uid arangodb --gid arangodb --pid-file /var/run/arangodb3/arangod.pid --temp.path /var/tmp/arangodb3 --log.foreground-tty true TimeoutStopSec=3600 TimeoutSec=3600 + Restart=on-failure +RestartSec=5 [Install] WantedBy=multi-user.target diff --git a/arangod/GeneralServer/GeneralServer.cpp b/arangod/GeneralServer/GeneralServer.cpp index 4da6f5e63f04..cfa194e22d80 100644 --- a/arangod/GeneralServer/GeneralServer.cpp +++ b/arangod/GeneralServer/GeneralServer.cpp @@ -26,6 +26,7 @@ #include "Basics/ConditionLocker.h" #include "Basics/MutexLocker.h" +#include "Basics/exitcodes.h" #include "Endpoint/EndpointList.h" #include "GeneralServer/GeneralDefinitions.h" #include "GeneralServer/GeneralListenTask.h" @@ -68,7 +69,7 @@ void GeneralServer::startListening() { << "'. Please check whether another instance is already " "running using this endpoint and review your endpoints " "configuration."; - FATAL_ERROR_EXIT(); + FATAL_ERROR_EXIT_CODE(TRI_EXIT_COULD_NOT_BIND_PORT); } } } diff --git a/arangod/RestServer/CheckVersionFeature.cpp b/arangod/RestServer/CheckVersionFeature.cpp index a00b98478725..db08e15b300d 100644 --- a/arangod/RestServer/CheckVersionFeature.cpp +++ b/arangod/RestServer/CheckVersionFeature.cpp @@ -32,6 +32,7 @@ #include "V8Server/v8-query.h" #include "V8Server/v8-vocbase.h" #include "VocBase/vocbase.h" +#include "Basics/exitcodes.h" using namespace arangodb; using namespace arangodb::application_features; @@ -154,7 +155,7 @@ void CheckVersionFeature::checkVersion() { LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "Database version check failed for '" << vocbase->name() << "'. Please inspect the logs for any errors"; - FATAL_ERROR_EXIT(); + FATAL_ERROR_EXIT_CODE(TRI_EXIT_VERSION_CHECK_FAILED); } else if (status == 3) { // this is safe to do even if further databases will be checked // because we will never set the status back to success @@ -182,8 +183,17 @@ void CheckVersionFeature::checkVersion() { if (*_result == 1) { *_result = EXIT_SUCCESS; } else if (*_result > 1) { - *_result = EXIT_FAILURE; - LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "Database version check failed"; - FATAL_ERROR_EXIT(); + if (*_result == 2) { + // downgrade needed + LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "Database version check failed: downgrade needed"; + FATAL_ERROR_EXIT_CODE(TRI_EXIT_DOWNGRADE_REQUIRED); + } else if (*_result == 3) { + LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "Database version check failed: upgrade needed"; + FATAL_ERROR_EXIT_CODE(TRI_EXIT_UPGRADE_REQUIRED); + } else { + LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "Database version check failed"; + FATAL_ERROR_EXIT_CODE(TRI_EXIT_VERSION_CHECK_FAILED); + } + FATAL_ERROR_EXIT_CODE(*_result); } } diff --git a/arangod/RestServer/LockfileFeature.cpp b/arangod/RestServer/LockfileFeature.cpp index 86666e9be485..b03873661425 100644 --- a/arangod/RestServer/LockfileFeature.cpp +++ b/arangod/RestServer/LockfileFeature.cpp @@ -24,6 +24,7 @@ #include "Basics/Exceptions.h" #include "Basics/FileUtils.h" #include "Basics/files.h" +#include "Basics/exitcodes.h" #include "Logger/Logger.h" #include "RestServer/DatabasePathFeature.h" @@ -58,7 +59,7 @@ void LockfileFeature::start() { LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "database is locked by process " << otherPID << "; please stop it first and check that the lockfile '" << _lockFilename << "' goes away. If you are sure no other arangod process is running, please remove the lockfile '" << _lockFilename << "' and try again"; } - FATAL_ERROR_EXIT(); + FATAL_ERROR_EXIT_CODE(TRI_EXIT_COULD_NOT_LOCK); } if (TRI_ExistsFile(_lockFilename.c_str())) { @@ -68,7 +69,7 @@ void LockfileFeature::start() { LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "failed to remove an abandoned lockfile in the database directory, please check the file permissions of the lockfile '" << _lockFilename << "': " << TRI_errno_string(res); - FATAL_ERROR_EXIT(); + FATAL_ERROR_EXIT_CODE(TRI_EXIT_COULD_NOT_LOCK); } } res = TRI_CreateLockFile(_lockFilename.c_str()); @@ -77,7 +78,7 @@ void LockfileFeature::start() { LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "failed to lock the database directory using '" << _lockFilename << "': " << TRI_errno_string(res); - FATAL_ERROR_EXIT(); + FATAL_ERROR_EXIT_CODE(TRI_EXIT_COULD_NOT_LOCK); } } diff --git a/cmake/ArangoDBInstall.cmake b/cmake/ArangoDBInstall.cmake index 5b1571c18faa..85f252fccdff 100644 --- a/cmake/ArangoDBInstall.cmake +++ b/cmake/ArangoDBInstall.cmake @@ -131,8 +131,6 @@ install( ### @brief detect if we're on a systemd enabled system; if install unit file. ################################################################################ -set(IS_SYSTEMD_INSTALL 0) -set(SYSTEMD_UNIT_DIR "") if (UNIX) if (${USE_ENTERPRISE}) set(SERVICE_NAME "arangodb3e") @@ -140,42 +138,68 @@ if (UNIX) set(SERVICE_NAME "arangodb3") endif () + # use pkgconfig for systemd detection find_package(PkgConfig QUIET) - pkg_check_modules(SYSTEMD systemd) - if (SYSTEMD_FOUND) - # cmake to old: pkg_get_variable(SYSTEMD_UNIT_DIR systemd systemdsystemunitdir) - execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} systemd --variable=systemdsystemunitdir - OUTPUT_VARIABLE SYSTEMD_UNIT_DIR - OUTPUT_STRIP_TRAILING_WHITESPACE) - set(IS_SYSTEMD_INSTALL 1) - - configure_file ( - ${ARANGODB_SOURCE_DIR}/Installation/systemd/arangodb3.service.in - ${PROJECT_BINARY_DIR}/arangodb3.service - NEWLINE_STYLE UNIX) - if (CMAKE_INSTALL_PREFIX AND NOT "${CMAKE_INSTALL_PREFIX}" STREQUAL "/") - set(SYSTEMD_UNIT_DIR "${CMAKE_INSTALL_PREFIX}/${SYSTEMD_UNIT_DIR}/") - endif() - install(FILES ${PROJECT_BINARY_DIR}/arangodb3.service - DESTINATION ${SYSTEMD_UNIT_DIR}/ - RENAME ${SERVICE_NAME}.service) - - configure_file ( - ${ARANGODB_SOURCE_DIR}/Installation/logrotate.d/arangod.systemd - ${PROJECT_BINARY_DIR}/arangod.systemd - NEWLINE_STYLE UNIX) - install( - FILES ${PROJECT_BINARY_DIR}/arangod.systemd - PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ - DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/logrotate.d - RENAME ${SERVICE_NAME}) - else () - configure_file ( - ${ARANGODB_SOURCE_DIR}/Installation/logrotate.d/arangod.sysv - ${PROJECT_BINARY_DIR}/arangod.sysv - NEWLINE_STYLE UNIX) - endif() -endif() + if(NOT PKG_CONFIG_FOUND) + message(STATUS "pkg-config not found - skipping systemd detection") + else() + set(IS_SYSTEMD_INSTALL 0) + set(SYSTEMD_UNIT_DIR "") + message(STATUS "detecting systemd") + pkg_check_modules(SYSTEMD systemd) + + if (SYSTEMD_FOUND) + message(STATUS "-- systemd found") + + # get systemd_unit_dir -- e.g /lib/systemd/system/ + # cmake to old: pkg_get_variable(SYSTEMD_UNIT_DIR systemd systemdsystemunitdir) + execute_process( + COMMAND ${PKG_CONFIG_EXECUTABLE} systemd --variable=systemdsystemunitdir + OUTPUT_VARIABLE SYSTEMD_UNIT_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + set(IS_SYSTEMD_INSTALL 1) + + # set prefix + if (CMAKE_INSTALL_PREFIX AND NOT "${CMAKE_INSTALL_PREFIX}" STREQUAL "/") + set(SYSTEMD_UNIT_DIR "${CMAKE_INSTALL_PREFIX}/${SYSTEMD_UNIT_DIR}/") + endif() + + # configure and install systemd service + configure_file ( + ${ARANGODB_SOURCE_DIR}/Installation/systemd/arangodb3.service.in + ${PROJECT_BINARY_DIR}/arangodb3.service + NEWLINE_STYLE UNIX + ) + install( + FILES ${PROJECT_BINARY_DIR}/arangodb3.service + DESTINATION ${SYSTEMD_UNIT_DIR}/ + RENAME ${SERVICE_NAME}.service + ) + + # configure and install logrotate file + configure_file ( + ${ARANGODB_SOURCE_DIR}/Installation/logrotate.d/arangod.systemd + ${PROJECT_BINARY_DIR}/arangod.systemd + NEWLINE_STYLE UNIX + ) + install( + FILES ${PROJECT_BINARY_DIR}/arangod.systemd + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ + DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/logrotate.d + RENAME ${SERVICE_NAME} + ) + + else () + message(STATUS "-- systemd not found") + configure_file ( + ${ARANGODB_SOURCE_DIR}/Installation/logrotate.d/arangod.sysv + ${PROJECT_BINARY_DIR}/arangod.sysv + NEWLINE_STYLE UNIX + ) + endif(SYSTEMD_FOUND) + endif(NOT PKG_CONFIG_FOUND) +endif(UNIX) ################################################################################ ### @brief propagate the locations into our programms: ################################################################################ @@ -203,6 +227,19 @@ install(FILES ${ICU_DT} DESTINATION "${INSTALL_ICU_DT_DEST}" RENAME ${ICU_DT_DEST}) +install(FILES "${CMAKE_SOURCE_DIR}/lib/Basics/exitcodes.dat" + DESTINATION "${INSTALL_ICU_DT_DEST}" + RENAME exitcodes.dat) + +install(FILES "${CMAKE_SOURCE_DIR}/Installation/arangodb-helper" + DESTINATION "${INSTALL_ICU_DT_DEST}" + RENAME arangodb-helper) + +install(FILES "${CMAKE_SOURCE_DIR}/Installation/arangodb-helper" + DESTINATION "${INSTALL_ICU_DT_DEST}" + RENAME arangodb-update-db) + + if (MSVC AND NOT(SKIP_PACKAGING)) # so we don't need to ship dll's twice, make it one directory: include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/InstallMacros.cmake) diff --git a/js/common/bootstrap/exitcodes.js b/js/common/bootstrap/exitcodes.js new file mode 100644 index 000000000000..e564ed9fd38c --- /dev/null +++ b/js/common/bootstrap/exitcodes.js @@ -0,0 +1,27 @@ +/*jshint maxlen: 240 */ +/*global require */ + +//////////////////////////////////////////////////////////////////////////////// +/// @brief auto-generated file generated from exitcodes.dat +//////////////////////////////////////////////////////////////////////////////// + +(function () { + "use strict"; + var internal = require("internal"); + + internal.exitCodes = { + "EXIT_SUCCESS" : { "code" : 0, "message" : "success" }, + "EXIT_FAILED" : { "code" : 1, "message" : "exit with error" }, + "EXIT_CODE_RESOLVING_FAILED" : { "code" : 2, "message" : "exit code resolving failed" }, + "EXIT_BINARY_NOT_FOUND" : { "code" : 5, "message" : "binary not found" }, + "EXIT_CONFIG_NOT_FOUND" : { "code" : 6, "message" : "config not found" }, + "EXIT_UPGRADE_FAILED" : { "code" : 10, "message" : "upgrade failed" }, + "EXIT_UPGRADE_REQUIRED" : { "code" : 11, "message" : "db upgrade required" }, + "EXIT_DOWNGRADE_REQUIRED" : { "code" : 12, "message" : "db downgrade required" }, + "EXIT_VERSION_CHECK_FAILED" : { "code" : 13, "message" : "version check failed" }, + "EXIT_ALREADY_RUNNING" : { "code" : 20, "message" : "already running" }, + "EXIT_COULD_NOT_BIND_PORT" : { "code" : 21, "message" : "port blocked" }, + "EXIT_COULD_NOT_LOCK" : { "code" : 22, "message" : "could not lock - another process could be running" } + }; +}()); + diff --git a/lib/Basics/Common.h b/lib/Basics/Common.h index 5ebebd187c78..97ac775f96de 100644 --- a/lib/Basics/Common.h +++ b/lib/Basics/Common.h @@ -212,13 +212,20 @@ typedef long suseconds_t; /// @brief aborts program execution, returning an error code /// if backtraces are enabled, a backtrace will be printed before -#define FATAL_ERROR_EXIT(...) \ +#define FATAL_ERROR_EXIT_CODE(code) \ do { \ TRI_LogBacktrace(); \ arangodb::Logger::flush(); \ arangodb::Logger::shutdown(); \ - TRI_EXIT_FUNCTION(EXIT_FAILURE, nullptr); \ - exit(EXIT_FAILURE); \ + TRI_EXIT_FUNCTION(code, nullptr); \ + exit(code); \ + } while (0) + +/// @brief aborts program execution, returning an error code +/// if backtraces are enabled, a backtrace will be printed before +#define FATAL_ERROR_EXIT(...) \ + do { \ + FATAL_ERROR_EXIT_CODE(EXIT_FAILURE); \ } while (0) /// @brief aborts program execution, calling std::abort diff --git a/lib/Basics/error.cpp b/lib/Basics/error.cpp index db310a0160aa..199ceda49a6a 100644 --- a/lib/Basics/error.cpp +++ b/lib/Basics/error.cpp @@ -22,6 +22,7 @@ //////////////////////////////////////////////////////////////////////////////// #include "Basics/Common.h" +#include "Basics/exitcodes.h" /// @brief error number and system error struct ErrorContainer { @@ -34,6 +35,8 @@ thread_local ErrorContainer LastError; /// @brief the error messages, will be read-only after initialization static std::unordered_map ErrorMessages; +static std::unordered_map ExitMessages; + /// @brief returns the last error int TRI_errno() { return LastError._number; } @@ -62,6 +65,16 @@ int TRI_set_errno(int error) { return error; } +/// @brief defines an exit code string +void TRI_set_exitno_string(int code, char const* msg) { + if (!ExitMessages.emplace(code, msg).second) { + // logic error, error number is redeclared + printf("Error: duplicate declaration of exit code %i in %s:%i\n", code, + __FILE__, __LINE__); + TRI_EXIT_FUNCTION(EXIT_FAILURE, nullptr); + } +} + /// @brief defines an error string void TRI_set_errno_string(int code, char const* msg) { if (!ErrorMessages.emplace(code, msg).second) { @@ -87,6 +100,7 @@ char const* TRI_errno_string(int code) { /// @brief initializes the error messages void TRI_InitializeError() { TRI_InitializeErrorMessages(); + TRI_InitializeExitMessages(); } /// @brief shuts down the error messages diff --git a/lib/Basics/error.h b/lib/Basics/error.h index 06318ac1ec28..614d7eea2258 100644 --- a/lib/Basics/error.h +++ b/lib/Basics/error.h @@ -70,4 +70,10 @@ void TRI_InitializeError(); void TRI_ShutdownError(); +//////////////////////////////////////////////////////////////////////////////// +/// @brief defines an exit string +//////////////////////////////////////////////////////////////////////////////// + +void TRI_set_exitno_string(int, char const*); + #endif diff --git a/lib/Basics/exitcodes.cpp b/lib/Basics/exitcodes.cpp new file mode 100644 index 000000000000..c4f11f6a0f07 --- /dev/null +++ b/lib/Basics/exitcodes.cpp @@ -0,0 +1,21 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief auto-generated file generated from exitcodes.dat +//////////////////////////////////////////////////////////////////////////////// + +#include "Basics/Common.h" +#include "./lib/Basics/exitcodes.h" + +void TRI_InitializeExitMessages () { + REG_EXIT(EXIT_SUCCESS, "success"); + REG_EXIT(EXIT_FAILED, "exit with error"); + REG_EXIT(EXIT_CODE_RESOLVING_FAILED, "exit code resolving failed"); + REG_EXIT(EXIT_BINARY_NOT_FOUND, "binary not found"); + REG_EXIT(EXIT_CONFIG_NOT_FOUND, "config not found"); + REG_EXIT(EXIT_UPGRADE_FAILED, "upgrade failed"); + REG_EXIT(EXIT_UPGRADE_REQUIRED, "db upgrade required"); + REG_EXIT(EXIT_DOWNGRADE_REQUIRED, "db downgrade required"); + REG_EXIT(EXIT_VERSION_CHECK_FAILED, "version check failed"); + REG_EXIT(EXIT_ALREADY_RUNNING, "already running"); + REG_EXIT(EXIT_COULD_NOT_BIND_PORT, "port blocked"); + REG_EXIT(EXIT_COULD_NOT_LOCK, "could not lock - another process could be running"); +} diff --git a/lib/Basics/exitcodes.dat b/lib/Basics/exitcodes.dat new file mode 100755 index 000000000000..b2e92f4f6060 --- /dev/null +++ b/lib/Basics/exitcodes.dat @@ -0,0 +1,27 @@ +################################################################################ +## Exit Codes +################################################################################ + +# general +EXIT_SUCCESS,0,"success","No error has occurred." +EXIT_FAILED,1,"exit with error","Will be returned when a general error occurred." +EXIT_CODE_RESOLVING_FAILED,2,"exit code resolving failed","fill me" + +EXIT_BINARY_NOT_FOUND,5,"binary not found","fill me" +EXIT_CONFIG_NOT_FOUND,6,"config not found","fill me" + +# internal +EXIT_UPGRADE_FAILED,10,"upgrade failed","Will be returned when the database upgrade failed" +EXIT_UPGRADE_REQUIRED,11,"db upgrade required","Will be returned when a database upgrade is required" +EXIT_DOWNGRADE_REQUIRED,12,"db downgrade required","Will be returned when a database upgrade is required" +EXIT_VERSION_CHECK_FAILED,13,"version check failed","Will be returned when there is a version mismatch" + +# startup +EXIT_ALREADY_RUNNING,20,"already running","Will be returned when arangod is already running according to PID-file" +EXIT_COULD_NOT_BIND_PORT,21,"port blocked","Will be returned when endpoint is taken by another process" +EXIT_COULD_NOT_LOCK,22,"could not lock - another process could be running","fill me" + +# network +#EXIT_NO_COORDINATOR +#EXIT_NO_AGENCY +#EXIT_NO_CONNECTIVITY diff --git a/lib/Basics/exitcodes.h b/lib/Basics/exitcodes.h new file mode 100644 index 000000000000..197177b7cc60 --- /dev/null +++ b/lib/Basics/exitcodes.h @@ -0,0 +1,170 @@ + +#ifndef TRIAGENS_BASICS_EXIT_CODES_H +#define TRIAGENS_BASICS_EXIT_CODES_H 1 + +//////////////////////////////////////////////////////////////////////////////// +/// Exit codes and meanings +/// +/// The following codes might be retured when exiting ArangoDB: +/// +#include "Basics/error.h" +/// - 0: @LIT{success} +/// No error has occurred. +/// - 1: @LIT{exit with error} +/// Will be returned when a general error occurred. +/// - 2: @LIT{exit code resolving failed} +/// fill me +/// - 5: @LIT{binary not found} +/// fill me +/// - 6: @LIT{config not found} +/// fill me +/// - 10: @LIT{upgrade failed} +/// Will be returned when the database upgrade failed +/// - 11: @LIT{db upgrade required} +/// Will be returned when a database upgrade is required +/// - 12: @LIT{db downgrade required} +/// Will be returned when a database upgrade is required +/// - 13: @LIT{version check failed} +/// Will be returned when there is a version mismatch +/// - 20: @LIT{already running} +/// Will be returned when arangod is already running according to PID-file +/// - 21: @LIT{port blocked} +/// Will be returned when endpoint is taken by another process +/// - 22: @LIT{could not lock - another process could be running} +/// fill me +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief helper macro to define an exit code string +//////////////////////////////////////////////////////////////////////////////// + +#define REG_EXIT(id, label) TRI_set_exitno_string(TRI_ ## id, label); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief register all exit codes for ArangoDB +//////////////////////////////////////////////////////////////////////////////// + +void TRI_InitializeExitMessages (); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 0: EXIT_SUCCESS +/// +/// success +/// +/// No error has occurred. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_EXIT_SUCCESS (0) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1: EXIT_FAILED +/// +/// exit with error +/// +/// Will be returned when a general error occurred. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_EXIT_FAILED (1) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 2: EXIT_CODE_RESOLVING_FAILED +/// +/// exit code resolving failed +/// +/// fill me +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_EXIT_CODE_RESOLVING_FAILED (2) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 5: EXIT_BINARY_NOT_FOUND +/// +/// binary not found +/// +/// fill me +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_EXIT_BINARY_NOT_FOUND (5) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 6: EXIT_CONFIG_NOT_FOUND +/// +/// config not found +/// +/// fill me +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_EXIT_CONFIG_NOT_FOUND (6) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 10: EXIT_UPGRADE_FAILED +/// +/// upgrade failed +/// +/// Will be returned when the database upgrade failed +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_EXIT_UPGRADE_FAILED (10) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 11: EXIT_UPGRADE_REQUIRED +/// +/// db upgrade required +/// +/// Will be returned when a database upgrade is required +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_EXIT_UPGRADE_REQUIRED (11) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 12: EXIT_DOWNGRADE_REQUIRED +/// +/// db downgrade required +/// +/// Will be returned when a database upgrade is required +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_EXIT_DOWNGRADE_REQUIRED (12) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 13: EXIT_VERSION_CHECK_FAILED +/// +/// version check failed +/// +/// Will be returned when there is a version mismatch +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_EXIT_VERSION_CHECK_FAILED (13) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 20: EXIT_ALREADY_RUNNING +/// +/// already running +/// +/// Will be returned when arangod is already running according to PID-file +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_EXIT_ALREADY_RUNNING (20) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 21: EXIT_COULD_NOT_BIND_PORT +/// +/// port blocked +/// +/// Will be returned when endpoint is taken by another process +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_EXIT_COULD_NOT_BIND_PORT (21) + +//////////////////////////////////////////////////////////////////////////////// +/// @brief 22: EXIT_COULD_NOT_LOCK +/// +/// could not lock - another process could be running +/// +/// fill me +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_EXIT_COULD_NOT_LOCK (22) + +#endif + diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 58b4cd53f42a..18db258b154c 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -171,6 +171,7 @@ add_library(${LIB_ARANGO} STATIC Basics/tri-zip.cpp Basics/vector.cpp Basics/voc-errors.cpp + Basics/exitcodes.cpp Basics/voc-mimetypes.cpp Basics/xxhash.cpp Endpoint/Endpoint.cpp diff --git a/utils/generateErrorfile.py b/utils/generateErrorfile.py old mode 100644 new mode 100755 index 23c18c55818e..6810509f6eae --- a/utils/generateErrorfile.py +++ b/utils/generateErrorfile.py @@ -1,3 +1,4 @@ +#!/usr/bin/python import csv, sys, os.path, re # wrap text after x characters diff --git a/utils/generateExitCodesFiles.py b/utils/generateExitCodesFiles.py new file mode 100755 index 000000000000..601dfebd1d5e --- /dev/null +++ b/utils/generateExitCodesFiles.py @@ -0,0 +1,227 @@ +#!/usr/bin/python +import csv, sys, os.path, re + +# wrap text after x characters +def wrap(string, width=80, ind1=0, ind2=0, prefix=''): + string = prefix + ind1 * " " + string + newstring = "" + string = string.replace("\n", " ") + + while len(string) > width: + marker = width - 1 + while not string[marker].isspace(): + marker = marker - 1 + + newline = string[0:marker] + "\n" + newstring = newstring + newline + string = prefix + ind2 * " " + string[marker + 1:] + + return newstring + string + + +# generate javascript file from errors +def genJsFile(errors): + jslint = "/*jshint maxlen: 240 */\n/*global require */\n\n" + + out = jslint \ + + prologue\ + + "(function () {\n"\ + + " \"use strict\";\n"\ + + " var internal = require(\"internal\");\n"\ + + "\n"\ + + " internal.exitCodes = {\n" + + # print individual errors + i = 0 + for e in errors: + name = "\"" + e[0] + "\"" + msg = e[2].replace("\n", " ").replace("\\", "").replace("\"", "\\\"") + out = out\ + + " " + name.ljust(30) + " : { \"code\" : " + e[1] + ", \"message\" : \"" + msg + "\" }" + + i = i + 1 + + if i < len(errors): + out = out + ",\n" + else: + out = out + "\n" + + + out = out\ + + " };\n"\ + + "}());\n"\ + + "\n" + + return out + +# generate NSIS implementation file from errors +def genNSISFile(errors, filename): + + impl = """ +!include "LogicLib.nsh" +!macro printExitCode exitCode Message + Push "${exitCode}" + Push "${Message}" + Call printExitCode +!macroend +Function printExitCode +pop $1 +pop $2 +${Switch} $0\n +""" + # print individual errors + for e in errors: + impl += """ + ${Case} %s # %s + MessageBox MB_ICONEXCLAMATION '$1:$\\r$\\n%s' + ; %s + ${Break} +""" % ( + e[1], + e[0], + e[2], + e[3] + ) + + impl = impl + """ +${EndSwitch} +FunctionEnd +""" + + return impl.replace("\r", "\r\n") + +# generate C implementation file from errors +def genCFile(errors, filename): + + headerfile = os.path.splitext(filename)[0] + ".h" + + impl = prologue\ + + "#include \"Basics/Common.h\"\n"\ + + "#include \"" + headerfile + "\"\n"\ + + "\n"\ + + "void TRI_InitializeExitMessages () {\n" + + # print individual errors + for e in errors: + msg = e[2].replace("\n", " ").replace("\\", "").replace("\"", "\\\"") + impl = impl\ + + " REG_EXIT(" + e[0] + ", \"" + msg + "\");\n" + + impl = impl\ + + "}\n" + + return impl + + +# generate C header file from errors +def genCHeaderFile(errors): + wiki = "////////////////////////////////////////////////////////////////////////////////\n"\ + + "/// Exit codes and meanings\n"\ + + "///\n"\ + + "/// The following codes might be retured when exiting ArangoDB:\n"\ + + "///\n"\ + + "#include \"Basics/error.h\"\n" + + for e in errors: + wiki = wiki\ + + "/// - " + e[1] + ": @LIT{" + e[2].replace("%", "\%").replace("<", "\<").replace(">", "\>") + "}\n"\ + + wrap(e[3], 80, 0, 0, "/// ") + "\n" + + wiki = wiki\ + + "////////////////////////////////////////////////////////////////////////////////\n" + + header = "\n"\ + + "#ifndef TRIAGENS_BASICS_EXIT_CODES_H\n"\ + + "#define TRIAGENS_BASICS_EXIT_CODES_H 1\n"\ + + "\n"\ + + wiki\ + + "\n"\ + + "////////////////////////////////////////////////////////////////////////////////\n"\ + + "/// @brief helper macro to define an exit code string\n"\ + + "////////////////////////////////////////////////////////////////////////////////\n"\ + + "\n"\ + + "#define REG_EXIT(id, label) TRI_set_exitno_string(TRI_ ## id, label);\n"\ + + "\n"\ + + "////////////////////////////////////////////////////////////////////////////////\n"\ + + "/// @brief register all exit codes for ArangoDB\n"\ + + "////////////////////////////////////////////////////////////////////////////////\n"\ + + "\n"\ + + "void TRI_InitializeExitMessages ();\n"\ + + "\n" + + # print individual errors + for e in errors: + header = header\ + + "////////////////////////////////////////////////////////////////////////////////\n"\ + + "/// @brief " + e[1] + ": " + e[0] + "\n"\ + + "///\n"\ + + wrap(e[2], 80, 0, 0, "/// ").replace("<", "\<").replace(">", "\>") + "\n"\ + + "///\n"\ + + wrap(e[3], 80, 0, 0, "/// ") + "\n"\ + + "////////////////////////////////////////////////////////////////////////////////\n"\ + + "\n"\ + + "#define TRI_" + e[0].ljust(61) + " (" + e[1] + ")\n"\ + + "\n" + + header = header\ + + "#endif\n"\ + + "\n" + + return header + + +# define some globals +prologue = "////////////////////////////////////////////////////////////////////////////////\n"\ + + "/// @brief auto-generated file generated from exitcodes.dat\n"\ + + "////////////////////////////////////////////////////////////////////////////////\n"\ + + "\n" + +if len(sys.argv) < 3: + print >> sys.stderr, "usage: %s " % sys.argv[0] + sys.exit() + +source = sys.argv[1] + +# read input file +errors = csv.reader(open(source, "rb")) +errorsList = [] + +r1 = re.compile(r'^#.*') + +for e in errors: + if len(e) == 0: + continue + + if r1.match(e[0]): + continue + + if e[0] == "" or e[1] == "" or e[2] == "" or e[3] == "": + print >> sys.stderr, "invalid exit code declaration file: %s" % (source) + sys.exit() + + errorsList.append(e) + +outfile = sys.argv[2] +extension = os.path.splitext(outfile)[1] +filename = outfile + +if extension == ".tmp": + filename = os.path.splitext(outfile)[0] + extension = os.path.splitext(filename)[1] + +if extension == ".js": + out = genJsFile(errorsList) +elif extension == ".h": + out = genCHeaderFile(errorsList) +elif extension == ".cpp": + out = genCFile(errorsList, filename) +elif extension == ".nsh": + out = genNSISFile(errorsList, filename) +else: + print >> sys.stderr, "usage: %s " % sys.argv[0] + sys.exit() + +outFile = open(outfile, "wb") +outFile.write(out); +outFile.close() +