#!/bin/bash # Copyright: 2023 Virtuozzo International GmbH # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. inherit default os envinfo hooks; include uninterract output php-common-deploy string net; include cartridge-common decrypt-passwd; DESCRIPTION="Operations with VCS"; VERSION="1"; DEFAULT_ACTION="Usage"; $PROGRAM 'sed'; $PROGRAM 'wget'; $PROGRAM 'svn'; $PROGRAM 'grep'; $PROGRAM 'git'; $PROGRAM 'curl'; $PROGRAM 'awk'; VCS_CONFIG_DIR="/var/lib/jelastic/vcs"; VCS_LOG_DIR="/var/log/jelastic/vcs"; DEFAULT_LOGIN="__GUEST__"; USERS_CRONFILE="/var/spool/cron/$($AWK -F ":" '{ print $1 }' <<< $DATA_OWNER )"; ROOT_CRONFILE="/var/spool/cron/root"; AUTOUPDATE_CRON_STRING="* * * * * jem vcs autoupdate"; REDEPLOY_CONF_FILE="/etc/jelastic/redeploy.conf"; BRANCH_NAME_FILTER="(\.\.|[[:space:]]|[\ []|[]\ ]|[\\@\,\"\'\|\~\^:\;\<\>\`\%\?\!\+\{\}\(\)]|\.$|\.lock$)"; GITSSH_SCRIPT="/var/lib/jelastic/libs/gitssh.sh" export GIT_SSH=${GITSSH_SCRIPT}; export GIT_SSL_NO_VERIFY="true"; export NO_EXPECT="false"; [ -z "$VCS_UPDATE_LOG" ] && VCS_UPDATE_LOG="${VCS_LOG_DIR}/vcs_update.log"; [ "x${COMPUTE_TYPE}" == "xcartridge" ] && restoreEnvironmentVariables && { [ -f ${CARTRIDGE_HOME}/jelastic/jelastic.conf ] && source ${CARTRIDGE_HOME}/jelastic/jelastic.conf; WEBROOT="${Webroot_Path}"; } function doUsage() { showUsageMessage; } ##### Internal functions ##### function checkVCSDirectories(){ [ ! -d "$VCS_CONFIG_DIR" ] && mkdir -p "$VCS_CONFIG_DIR"; [ ! -d "$VCS_LOG_DIR" ] && mkdir -p "$VCS_LOG_DIR"; } function recoverBrokenMountPoints(){ local mount_points=$(mount | $GREP -o -P '(?<=deleted\)).*(?=type)'); [ ! -z "$mount_points" ] && for mount_point in $mount_points do umount "$mount_point"; mount "$mount_point"; done return 0; } function parseArguments() { while [ "$1" != "" ]; do case $1 in -n | --project-name ) shift; PROJECT_NAME=$1; ;; -t | --vcs-type ) shift; VCS_TYPE=$1; ;; -u | --url ) shift; URL=$1; ;; -l | --login ) shift; LOGIN=$1; ;; -p | --password ) shift; PASSWORD=$1; ;; -b | --branch ) shift; BRANCH=$1; ;; -o | --old-project-name ) shift; OLD_PROJECT_NAME=$1; ;; -c | --context ) shift; CONTEXT=$1; ;; -e | --environment ) shift; ENVIRONMENT=$1; ;; -au | --autoupdate ) shift; AUTOUPDATE=$1; ;; -m | --updateinverval ) shift; UPDATE_INTERVAL=$1; ;; -k | --authkey ) shift; AUTHORIZATION_KEY_VAL="$1"; ;; -r | --autoresolveconflict) shift; GIT_AUTORESOLVE_CONFLICT="$1"; ;; -a | --atomicdeploy) shift; ATOMIC_DEPLOY="$1"; ;; --subdirectory ) shift; BUILDDIR=$1; ;; -g | --nodegroup ) shift; NODE_GROUP=$1 ;; --repohash ) shift; REPO_HASH=$1 ;; esac shift done PASSWORD=$(getPassword $PASSWORD); [ "x${COMPUTE_TYPE}" == "xapache-ruby" -o "x${COMPUTE_TYPE}" == "xnginx-ruby" ] || [ "x${COMPUTE_TYPE}" == "xcartridge" -a "x${Engine_Type}" == "xruby" ] && { [ "x${PROJECT_NAME}" == "xROOT" ] && [ ! -z ${OLD_PROJECT_NAME} ] && PROJECT_NAME=${OLD_PROJECT_NAME}; [ ! -z "$PROJECT_NAME" ] && { bundle_type="${PROJECT_NAME}" ; PROJECT_NAME="ROOT"; } ; } [ "${COMPUTE_TYPE}" == "nodejs" ] && { PROJECT_NAME="ROOT"; } [ -z "${ATOMIC_DEPLOY}" ] && { ATOMIC_DEPLOY="false"; } } function writeProjectConfig(){ [ "x${COMPUTE_TYPE}" == "xapache-ruby" -o "x${COMPUTE_TYPE}" == "xnginx-ruby" ] || [ "x${COMPUTE_TYPE}" == "xcartridge" -a "x${Engine_Type}" == "xruby" ] && { echo "$bundle_type" > /var/lib/jelastic/env PROJECT_NAME="ROOT" } enableVCSLibrary; [ "x${COMPUTE_TYPE}" != "xmaven" ] && LAST_DEPLOYED_COMMIT=$(getLastRepoCommit); PROJECT_CONFIG="${VCS_CONFIG_DIR}/${PROJECT_NAME}.properties"; echo "PROJECT_NAME=${PROJECT_NAME}" > $PROJECT_CONFIG; echo "VCS_TYPE=${VCS_TYPE}" >> $PROJECT_CONFIG; echo "URL=${URL}" >> $PROJECT_CONFIG; echo "LOGIN=${LOGIN}" >> $PROJECT_CONFIG; echo PASSWORD="'"${PASSWORD}"'" >> $PROJECT_CONFIG; echo "BRANCH=${BRANCH}" >> $PROJECT_CONFIG; echo "ENVIRONMENT=${ENVIRONMENT}" >> $PROJECT_CONFIG; echo "CONTEXT=${CONTEXT}" >> $PROJECT_CONFIG; echo "AUTOUPDATE=${AUTOUPDATE}" >> $PROJECT_CONFIG; echo "UPDATE_INTERVAL=${UPDATE_INTERVAL}" >> $PROJECT_CONFIG; local timestamp=`date +%s`; echo "LASTUPDATE=$timestamp" >> $PROJECT_CONFIG; echo "LAST_DEPLOYED_COMMIT=${LAST_DEPLOYED_COMMIT}" >> $PROJECT_CONFIG; echo "NEED_REDEPLOY=$NEED_REDEPLOY" >> $PROJECT_CONFIG; echo "GIT_AUTORESOLVE_CONFLICT=$GIT_AUTORESOLVE_CONFLICT" >> $PROJECT_CONFIG; echo "ATOMIC_DEPLOY=$ATOMIC_DEPLOY" >> $PROJECT_CONFIG; echo "NODE_GROUP=$NODE_GROUP" >> $PROJECT_CONFIG; echo "REPO_HASH=$REPO_HASH" >> $PROJECT_CONFIG; if [ -z "$AUTHORIZATION_KEY_VAL" ] ; then if [ -e ${VCS_CONFIG_DIR}/${PROJECT_NAME}.key ]; then echo "AUTHORIZATION_KEY=${VCS_CONFIG_DIR}/${PROJECT_NAME}.key" >> $PROJECT_CONFIG; else echo "AUTHORIZATION_KEY=" >> $PROJECT_CONFIG; fi else echo "AUTHORIZATION_KEY=${VCS_CONFIG_DIR}/${PROJECT_NAME}.key" >> $PROJECT_CONFIG; echo "$AUTHORIZATION_KEY_VAL" > "${VCS_CONFIG_DIR}/${PROJECT_NAME}".key chmod 600 "${VCS_CONFIG_DIR}/${PROJECT_NAME}".key fi [ -z "$BUILDDIR" ] || echo "BUILDDIR=$BUILDDIR" >> $PROJECT_CONFIG; } function readProjectConfig(){ local project_to_read; [ "x${COMPUTE_TYPE}" == "xapache-ruby" -o "x${COMPUTE_TYPE}" == "xnginx-ruby" ] || [ "x${COMPUTE_TYPE}" == "xcartridge" -a "x${Engine_Type}" == "xruby" ] && { bundle_type=`cat /var/lib/jelastic/env` PROJECT_NAME="ROOT" } [ -z $1 ] && project_to_read=${PROJECT_NAME} || project_to_read="$1"; if [ -e "${VCS_CONFIG_DIR}/${project_to_read}.properties" ] ; then source "${VCS_CONFIG_DIR}/${project_to_read}.properties"; [ -z $VCS_TYPE ] && { return 1; } [ ! -z "$AUTHORIZATION_KEY" -a -f "$AUTHORIZATION_KEY" ] && { AUTHORIZATION_KEY_VAL=`cat $AUTHORIZATION_KEY`; export AUTHORIZATION_KEY; } [ -z "$GIT_AUTORESOLVE_CONFLICT" ] && GIT_AUTORESOLVE_CONFLICT=true ; # [ ! -z "$AUTHORIZATION_KEY" ] && { # export AUTHORIZATION_KEY; # } else #echo "Couldn't find project options!"; return 1; fi return 0; } function enableVCSLibrary(){ [ -z $VCS_TYPE ] && { echo "Unknown VCS type!"; return 1; } case ${VCS_TYPE} in SVN) local vcslib="svn"; ;; GIT) local vcslib="git"; ;; esac include $vcslib; } function _deployLog(){ echo -en "$(date) "$@ '\n' | tee -a "$DEPLOY_LOG" >> "$VCS_UPDATE_LOG"; } ##### External functions ##### function doCreateProject(){ checkVCSDirectories; parseArguments "$@"; isValidURL $URL || { writeJSONResponseErr "result=>4050" "message=>URL is not valid!"; return 1; }; [ -n "$BRANCH" ] && { if [[ $BRANCH =~ $BRANCH_NAME_FILTER ]]; then writeJSONResponseErr "result=>4050" "message=>Branch name is not valid!"; return 1; fi } local incorrect_login_regex="[~\!\#\$%^&\*\(\)\{\}\\\/=]"; [[ $LOGIN =~ $incorrect_login_regex ]] && { writeJSONResponseErr "result=>4053" "message=>Login is not valid!"; return 1; }; [ -z $LOGIN ] && LOGIN="$DEFAULT_LOGIN"; doEnableScheduler; writeProjectConfig && { [ ${COMPUTE_TYPE} == "apache-ruby" -o ${COMPUTE_TYPE} == "nginx-ruby" ] || [ "x${COMPUTE_TYPE}" == "xcartridge" -a "x${Engine_Type}" == "xruby" ] && { PROJECT_NAME=${bundle_type}; reloadServiceSilent "$SERVICE"; } && [ ! -z $CONTEXT ] && [ ! -z $ENVIRONMENT ] && writeJSONResponseOut "result=>0" "message=>Project $PROJECT_NAME was successfully created" "project_name=>${PROJECT_NAME}" "vcs_type=>${VCS_TYPE}" "url=>${URL}" "login=>${LOGIN}" "branch=>${BRANCH}" "environment=>${ENVIRONMENT}" "context=>${CONTEXT}" "autoupdate=>${AUTOUPDATE}" "interval=>${UPDATE_INTERVAL}" "autoresolveconflict=>${GIT_AUTORESOLVE_CONFLICT}" || writeJSONResponseOut "result=>0" "message=>Project $PROJECT_NAME was successfully created" "project_name=>${PROJECT_NAME}" "vcs_type=>${VCS_TYPE}" "url=>${URL}" "login=>${LOGIN}" "branch=>${BRANCH}" "autoupdate=>${AUTOUPDATE}" "interval=>${UPDATE_INTERVAL}" "autoresolveconflict=>${GIT_AUTORESOLVE_CONFLICT}" "atomic_deploy=>${ATOMIC_DEPLOY}" "nodegroup=>${NODE_GROUP}" "repohash=>${REPO_HASH}"; } || { writeJSONResponseErr "result=>4001" "message=>Error while creating project config!"; return 1; }; } function doDeleteProject(){ parseArguments "$@"; [ -z $PROJECT_NAME ] && { writeJSONResponseErr "result=>4005" "message=>You must specify project name!"; return 1; } [ -d "${WEBROOT}/${PROJECT_NAME}" ] && rm -Rf ${WEBROOT}/${PROJECT_NAME}; [[ "$PROJECT_NAME" == "ROOT" ]] && { rm -rf ${WEBROOT}/ROOT; cd ${WEBROOT}; ROOT_DIRS=$(ls ${WEBROOT} | $GREP "^ROOT_[0-9]\{4\}.[0-9]\{2\}.[0-9]\{2\}-[0-9]\{2\}.[0-9]\{2\}.[0-9]\{2\}$"); rm -rf ${ROOT_DIRS} && _deployLog "Removing deprecated ROOT context directories ${ROOT_DIRS}"; mkdir -p ${WEBROOT}/${PROJECT_NAME}; updateOwnership ${WEBROOT}/${PROJECT_NAME} > /dev/null 2>&1; [ -L ${WEBROOT}/../ROOT ] && { rm -f ${WEBROOT}/../ROOT; ln -s ${WEBROOT}/${PROJECT_NAME} ${WEBROOT}/../ROOT; } } [ -f "${VCS_CONFIG_DIR}/${PROJECT_NAME}.key" ] && rm -f "${VCS_CONFIG_DIR}/${PROJECT_NAME}.key"; [ -f "${VCS_CONFIG_DIR}/${PROJECT_NAME}.properties" ] && rm -f "${VCS_CONFIG_DIR}/${PROJECT_NAME}.properties"; writeJSONResponseOut "result=>0" "message=>Project $PROJECT_NAME was succesfully deleted"; [ "`find ${VCS_CONFIG_DIR} -type f`" ] || doDisableScheduler; [ ${COMPUTE_TYPE} == "cartridge" ] && recoverBrokenMountPoints; removeHooks ${PROJECT_NAME} ; } function doUpdate(){ parseArguments "$@"; readProjectConfig || { writeJSONResponseErr "result=>4006" "message=>Error while reading project config!"; return 1; }; enableVCSLibrary; applyHook ${PROJECT_NAME} preUpdate || { writeJSONResponseErr "result=>4127" "message=>Pre-update hook execution failed. See hooks log for details: ${HOOKS_LOG}"; return 1; }; [ "x${COMPUTE_TYPE}" != "xmaven" ] && { applyHook ${PROJECT_NAME} preDeploy || { writeJSONResponseErr "result=>4125" "message=>Pre-deploy hook execution failed. See hooks log for details: ${HOOKS_LOG}"; return 1; }; } if [ "x${COMPUTE_TYPE}" == "xapache-php" -o "x${COMPUTE_TYPE}" == "xnginx-php" -o "x${COMPUTE_TYPE}" == "xlitespeed" -o "x${COMPUTE_TYPE}" == "xlemp" -o "x${COMPUTE_TYPE}" == "xllsmp" ] && [ "x${PROJECT_NAME}" == "xROOT" ] && [ "x${ATOMIC_DEPLOY}" == "xtrue" ]; then local NEXT_DIR=ROOT_`date +%Y.%m.%d-%H.%M.%S`; if [ -h ${WEBROOT}/ROOT ] ; then local CURRENT_DIR=`readlink ${WEBROOT}/ROOT | $GREP -o "ROOT_[0-9.-]*"`; [ ! -d ${WEBROOT}/${CURRENT_DIR} ] && CURRENT_DIR=`ls ${WEBROOT} | $GREP "^ROOT_[0-9]\{4\}.[0-9]\{2\}.[0-9]\{2\}-[0-9]\{2\}.[0-9]\{2\}.[0-9]\{2\}$" | tail -n1`; if [ -n "${CURRENT_DIR}" ]; then local PREVIOUS_DIR=`ls ${WEBROOT} | $GREP "^ROOT_[0-9]\{4\}.[0-9]\{2\}.[0-9]\{2\}-[0-9]\{2\}.[0-9]\{2\}.[0-9]\{2\}$" | $GREP -v "$CURRENT_DIR" | head -1`; else local PREVIOUS_DIR=`ls ${WEBROOT} | $GREP "^ROOT_[0-9]\{4\}.[0-9]\{2\}.[0-9]\{2\}-[0-9]\{2\}.[0-9]\{2\}.[0-9]\{2\}$" | head -1`; fi else CURRENT_DIR=`ls ${WEBROOT} | $GREP "^ROOT_[0-9]\{4\}.[0-9]\{2\}.[0-9]\{2\}-[0-9]\{2\}.[0-9]\{2\}.[0-9]\{2\}$" | tail -n1` [ -n "${CURRENT_DIR}" ] && { ln -sfT "${WEBROOT}/${CURRENT_DIR}" ${WEBROOT}/ROOT && _deployLog "Swithing the ROOT context to ${CURRENT_DIR}"; updateOwnership ${WEBROOT}/ROOT; } fi if [[ -d ${WEBROOT}/ROOT && ! -h ${WEBROOT}/ROOT ]] ; then if [ "$UID" == '0' ]; then chown -R ${DATA_OWNER} ${WEBROOT}/ROOT; fi mv -f ${WEBROOT}/ROOT ${WEBROOT}/$NEXT_DIR && _deployLog "Copying content of the ROOT directory to $NEXT_DIR"; fi if [ -z "${PREVIOUS_DIR}" ] ;then local DIR_AMOUNT=`ls ${WEBROOT} | $GREP "^ROOT_[0-9]\{4\}.[0-9]\{2\}.[0-9]\{2\}-[0-9]\{2\}.[0-9]\{2\}.[0-9]\{2\}$" | wc -l`; [ ${DIR_AMOUNT} -gt 1 ] && PREVIOUS_DIR=`ls ${WEBROOT} | $GREP "^ROOT_[0-9]\{4\}.[0-9]\{2\}.[0-9]\{2\}-[0-9]\{2\}.[0-9]\{2\}.[0-9]\{2\}$" | tail -n2 | head -1`; fi [ -n "${PREVIOUS_DIR}" ] && rm -rf ${WEBROOT}/${PREVIOUS_DIR} && _deployLog "Removing old deprecated context directory ${PREVIOUS_DIR}"; if [ -n "${CURRENT_DIR}" ] ;then if [ "$UID" == '0' ]; then chown -R ${DATA_OWNER} ${WEBROOT}/${CURRENT_DIR}; fi if which rsync &>>/dev/null; then rsync -alrp --inplace --quiet --ignore-errors ${WEBROOT}/${CURRENT_DIR}/ ${WEBROOT}/${NEXT_DIR} 2>&1; local result=$?; if [ $result -ne 0 ]; then writeJSONResponseErr "result=>4075" "message=>Rsync error code $result (probably because of unsufficient disk space)" && _deployLog "Cannot move application from ${CURRENT_DIR} to ${NEXT_DIR} (probably beca use of unsufficient disk space). rsync exit code is $result"; return 1; else _deployLog "Copying application files from ${CURRENT_DIR} to ${NEXT_DIR} - successful"; fi else cp -rf ${WEBROOT}/${CURRENT_DIR}/ ${WEBROOT}/${NEXT_DIR} 2>&1; if [ $? -ne 0 ]; then writeJSONResponseErr "result=>4075" "message=>No free diskspace" && _deployLog "Not enough disk space. Cannot move application from ${CURRENT_DIR} to ${NEXT_DIR}"; return 1; else _deployLog "Copying application files from ${CURRENT_DIR} to ${NEXT_DIR}" fi fi fi J_OLD_PROJECT_NAME="${PROJECT_NAME}"; PROJECT_NAME="${NEXT_DIR}" if [ -d "${WEBROOT}/${PROJECT_NAME}/.$(toLowerCase ${VCS_TYPE})" ] ; then updateProject 2>>"$VCS_UPDATE_LOG" result=$? updateOwnership ${WEBROOT}/${PROJECT_NAME}; if [[ $result == 0 ]]; then ln -sfT "${WEBROOT}/${PROJECT_NAME}" ${WEBROOT}/ROOT && _deployLog "Switching the document root to new context directory ${PROJECT_NAME}"; updateOwnership ${WEBROOT}/ROOT; [ -z "${J_OLD_PROJECT_NAME}" ] || { PROJECT_NAME="${J_OLD_PROJECT_NAME}"; writeProjectConfig; } else if [[ $result == 2 ]]; then writeJSONResponseErr "result=>4211" "message=>Token required"; else writeJSONResponseErr "result=>4000" "message=>Authentication failed or url is incorrect"; fi return 1; fi else doCheckout result=$? if [[ $result == 2 ]]; then writeJSONResponseErr "result=>4211" "message=>Token required"; die -q; elif [[ $result != 0 ]]; then writeJSONResponseErr "result=>4000" "message=>Authentication failed or url is incorrect"; die -q; fi updateOwnership ${WEBROOT}/${PROJECT_NAME}; ln -sfT "${WEBROOT}/${PROJECT_NAME}" ${WEBROOT}/ROOT && _deployLog "Switching the document root to new context directory ${PROJECT_NAME}"; updateOwnership ${WEBROOT}/ROOT; [ -z "${J_OLD_PROJECT_NAME}" ] || { PROJECT_NAME="${J_OLD_PROJECT_NAME}"; writeProjectConfig; } fi else if [ "x${PROJECT_NAME}" == "xROOT" ] && [ -L ${WEBROOT}/ROOT ]; then TARGET_DIR=`readlink ${WEBROOT}/ROOT | $GREP -o "ROOT_[0-9.-]*"`; [ ! -d ${WEBROOT}/${TARGET_DIR} ] && local TARGET_DIR=`ls ${WEBROOT} | $GREP "^ROOT_[0-9]\{4\}.[0-9]\{2\}.[0-9]\{2\}-[0-9]\{2\}.[0-9]\{2\}.[0-9]\{2\}$" | tail -n1`; rm -f ${WEBROOT}/ROOT; if [ -n "${TARGET_DIR}" ] ;then if [ ! -d ${WEBROOT}/ROOT ] ;then mkdir ${WEBROOT}/ROOT; else shopt -s dotglob; rm -rf ${WEBROOT}/ROOT/* && _deployLog "Removing the content of current ROOT directory"; shopt -u dotglob; fi if [ "$UID" == '0' ]; then chown -R ${DATA_OWNER} "${WEBROOT}/${TARGET_DIR}/"; fi shopt -s dotglob; set +f mv -f ${WEBROOT}/${TARGET_DIR}/* ${WEBROOT}/ROOT; if [ $? -ne 0 ]; then shopt -u dotglob; writeJSONResponseErr "result=>4075" "message=>No free diskspace" && _deployLog "Not enough disk space. Cannot move application to ROOT directory"; return 1; fi shopt -u dotglob; fi cd ${WEBROOT}; ROOT_DIRS=`ls ${WEBROOT} | $GREP "^ROOT_[0-9]\{4\}.[0-9]\{2\}.[0-9]\{2\}-[0-9]\{2\}.[0-9]\{2\}.[0-9]\{2\}$"`; rm -rf ${ROOT_DIRS} && _deployLog "Removing deprecated ROOT context directories ${ROOT_DIRS}"; cd /; fi if [ -d "${WEBROOT}/${PROJECT_NAME}/.$(toLowerCase ${VCS_TYPE})" ] ; then updateProject 2>>"$VCS_UPDATE_LOG" result=$? updateOwnership ${WEBROOT}/${PROJECT_NAME}; if [[ $result == 0 ]]; then writeProjectConfig; else if [[ $result == 2 ]]; then writeJSONResponseErr "result=>4211" "message=>Token required"; else writeJSONResponseErr "result=>4000" "message=>Authentication failed or url is incorrect"; fi return $result; fi else [ -d "${WEBROOT}/${PROJECT_NAME}" ] && rm -Rf "${WEBROOT}/${PROJECT_NAME}/"; doCheckout result=$? if [[ $result == 2 ]]; then writeJSONResponseErr "result=>4211" "message=>Token required"; die -q; elif [[ $result != 0 ]]; then writeJSONResponseErr "result=>4000" "message=>Authentication failed or url is incorrect"; die -q; fi updateOwnership ${WEBROOT}/${PROJECT_NAME}; writeProjectConfig; fi fi [ "x${COMPUTE_TYPE}" != "xmaven" ] && isFunction "setContext" && setContext ${PROJECT_NAME}; [ "x${COMPUTE_TYPE}" == "xcartridge" ] && recoverBrokenMountPoints && service cartridge build >> $ACTIONS_LOG 2>&1 && service cartridge deploy >> $ACTIONS_LOG 2>&1; applyHook ${PROJECT_NAME} postUpdate || { writeJSONResponseErr "result=>4128" "message=>Post-update hook execution failed. See hooks log for details: ${HOOKS_LOG}"; return 1; }; [ "x${COMPUTE_TYPE}" != "xmaven" ] && { applyHook ${PROJECT_NAME} postDeploy || { local hook_error_message="message=>Post-deploy hook execution failed. See hooks log for details: ${HOOKS_LOG}" if [ "x${ATOMIC_DEPLOY}" == "xtrue" ]; then CURRENT_DIR=$(ls ${WEBROOT} | $GREP "^ROOT_[0-9]\{4\}.[0-9]\{2\}.[0-9]\{2\}-[0-9]\{2\}.[0-9]\{2\}.[0-9]\{2\}$" | tail -n1); PREVIOUS_DIR=$(ls -1 ${WEBROOT} | grep "^ROOT_[0-9]\{4\}.[0-9]\{2\}.[0-9]\{2\}-[0-9]\{2\}.[0-9]\{2\}.[0-9]\{2\}$" | tail -n2|head -n 1); if [ -n "${PREVIOUS_DIR}" ]; then ln -sfT ${WEBROOT}/${PREVIOUS_DIR} ${WEBROOT}/ROOT && _deployLog "Switching the ROOT context back to ${PREVIOUS_DIR} directory due to failed postDeploy hook execution."; chown -R ${DATA_OWNER} ${WEBROOT}/ROOT; hook_error_message="${hook_error_message}. ROOT context now points to directory ${WEBROOT}/${PREVIOUS_DIR}." if [ "${PREVIOUS_DIR}" != "${CURRENT_DIR}" ]; then rm -rf ${WEBROOT}/${CURRENT_DIR} fi fi fi writeJSONResponseErr "result=>4126" "${hook_error_message}"; return 1; }; } writeJSONResponseOut "result=>0" "message=>Project updated successfully"; return 0; } function doCallProjectUpdate(){ local project_name="$1"; local last_repo_commit=$(getLastRepoCommit $project_name); [ "x${last_repo_commit}" == "x${LAST_DEPLOYED_COMMIT}" ] && return 0; getInfraAddresses infraAddr; [[ -z "${CORE_ADDR}" ]] && { error "Cannot obtain core address"; return 1; } $CURL "http://${CORE_ADDR}/JElastic/env/build/rest/builddeploy?appid=01234567890123456789012345678901&projectName=$project_name" &>>"$JEM_CALLS_LOG"; LAST_DEPLOYED_COMMIT=$last_repo_commit; writeProjectConfig; } function doAutoUpdate(){ NO_EXPECT="true"; UPDATE_IS_OK="false"; [ "`find ${VCS_CONFIG_DIR} -type f`" ] && { for project in $( ls ${VCS_CONFIG_DIR}/*.properties ); do source ${project} enableVCSLibrary; [[ "x$AUTOUPDATE" == "xtrue" ]] && { LastRemoteCommitVal=$(getLastRemoteCommit) [[ ${LAST_DEPLOYED_COMMIT} == $LastRemoteCommitVal ]] && continue ; [[ $LastRemoteCommitVal == "00000000000" ]] && continue ; local next_allowed_update=$(( $LASTUPDATE + $UPDATE_INTERVAL * 60 )); local current_timestamp=`date +%s`; [[ $next_allowed_update -lt $current_timestamp ]] && doUpdate >> $JEM_CALLS_LOG && UPDATE_IS_OK="true" && writeProjectConfig; [[ "x${COMPUTE_TYPE}" == "xmaven" ]] && [[ "x${UPDATE_IS_OK,,}" == "xtrue" ]] && doCallProjectUpdate $PROJECT_NAME; } done } return 0 ; } function doEnableScheduler(){ if [ -f $REDEPLOY_CONF_FILE ]; then $GREP -q "^$ROOT_CRONFILE" $REDEPLOY_CONF_FILE || echo "$ROOT_CRONFILE" >> $REDEPLOY_CONF_FILE; fi [ -f $ROOT_CRONFILE ] && $GREP -q "\^$AUTOUPDATE_CRON_STRING" $ROOT_CRONFILE || { echo "$AUTOUPDATE_CRON_STRING" >> $ROOT_CRONFILE; chmod 0644 $ROOT_CRONFILE; } } function doDisableScheduler(){ [ -f $ROOT_CRONFILE ] && $SED -i "/$AUTOUPDATE_CRON_STRING/d" $ROOT_CRONFILE; } function doGetProject(){ parseArguments "$@"; readProjectConfig || { writeJSONResponseErr "result=>4006" "message=>Error while reading project config!"; return 1; }; [ ${COMPUTE_TYPE} == "apache-ruby" -o ${COMPUTE_TYPE} == "nginx-ruby" ] || [ "x${COMPUTE_TYPE}" == "xcartridge" -a "x${Engine_Type}" == "xruby" ] && { PROJECT_NAME=${bundle_type} } VAL="project_name=>${PROJECT_NAME} vcs_type=>${VCS_TYPE} url=>${URL} login=>${LOGIN} branch=>${BRANCH} interval=>${UPDATE_INTERVAL} autoupdate=>${AUTOUPDATE} atomicdeploy=>${ATOMIC_DEPLOY}"; [ ! -z "$CONTEXT" ] && [ ! -z "$ENVIRONMENT" ] && { VAL=$VAL" environment=>${ENVIRONMENT} context=>${CONTEXT}" ; } [ ! -z "$AUTHORIZATION_KEY_VAL" ] && { hash=`echo "$AUTHORIZATION_KEY_VAL" | md5sum | $AWK '{print $1}'`; VAL=$VAL" hash=>$hash"; } [ ! -z $GIT_AUTORESOLVE_CONFLICT ] && { VAL=$VAL" resolveconflict=>${GIT_AUTORESOLVE_CONFLICT}"; } [ ! -z "$BUILDDIR" ] && { VAL=$VAL" subdirectory=>${BUILDDIR}"; } [ ! -z "$NODE_GROUP" ] && { VAL=$VAL" nodegroup=>${NODE_GROUP}"; } [ ! -z "$REPO_HASH" ] && { VAL=$VAL" repohash=>${REPO_HASH}"; } writeJSONResponseOut "result=>0" ${VAL} ; } function doEditProject(){ local repository_url_was_changed="false"; parseArguments "$@"; [ "${COMPUTE_TYPE}" == "apache-ruby" -o "${COMPUTE_TYPE}" == "nginx-ruby" ] || [ "x${COMPUTE_TYPE}" == "xcartridge" -a "x${Engine_Type}" == "xruby" ] && { OLD_PROJECT_NAME="ROOT" } CLEAN_KEY=0; CLEAN_PASSWORD=0; [ ! -z "$PASSWORD" ] && { # password was in params, clean key CLEAN_KEY=1; } [ ! -z "$AUTHORIZATION_KEY_VAL" ] && { # ssh key was in params, clean password CLEAN_PASSWORD=1; [ "$CLEAN_KEY" -eq 1 ] && { writeJSONResponseErr "result=>4017" "message=>Project edit failed"; return 1; } } [ -n "$BRANCH" ] && { if [[ $BRANCH =~ $BRANCH_NAME_FILTER ]]; then writeJSONResponseErr "result=>4050" "message=>Branch name is not valid!"; return 1; fi } #[ ! -z $URL ] && repository_url_was_changed="true"; isValidURL $URL || { writeJSONResponseErr "result=>4050" "message=>URL is not valid!"; return 1; }; readProjectConfig $OLD_PROJECT_NAME || { writeJSONResponseErr "result=>4006" "message=>Error while reading project config!"; return 1; }; doEnableScheduler; [ ! -z "$URL" ] && OLDURL="$URL"; [ ! -z "$PASSWORD" ] && OLDPASSWORD="$PASSWORD"; [ ! -z "$LOGIN" ] && OLDLOGIN="$LOGIN"; parseArguments "$@"; [ "${COMPUTE_TYPE}" == "apache-ruby" -o "${COMPUTE_TYPE}" == "nginx-ruby" ] || [ "x${COMPUTE_TYPE}" == "xcartridge" -a "x${Engine_Type}" == "xruby" ] && { OLD_PROJECT_NAME="ROOT"; } [ ! -z "$URL" ] && NEWURL=$URL; [ "x$OLDURL" != "x$NEWURL" -o "x$OLDPASSWORD" != "x$PASSWORD" -o "x$OLDLOGIN" != "x$LOGIN" ] && repository_url_was_changed="true"; [ "$CLEAN_KEY" -eq 1 ] && { AUTHORIZATION_KEY_VAL="" ; AUTHORIZATION_KEY=""; rm -rf "${VCS_CONFIG_DIR}/${PROJECT_NAME}.key"; } [ "$CLEAN_PASSWORD" -eq 1 ] && { PASSWORD=""; } if [ "x$repository_url_was_changed" == "xtrue" -a -d "${WEBROOT}/${PROJECT_NAME}/.$(toLowerCase ${VCS_TYPE})" ] ; then enableVCSLibrary; vcsChangeUrl; changeUrlresult=$?; else changeUrlresult=0; fi ( [[ -n "${OLD_PROJECT_NAME}" ]] && [[ -n "${PROJECT_NAME}" ]] && [[ "$OLD_PROJECT_NAME" != "$PROJECT_NAME" ]] ) && { # doAction deploy rename -o $OLD_PROJECT_NAME -n $PROJECT_NAME > /dev/null 2>&1; if [ ! -d "${WEBROOT}/${PROJECT_NAME}/" ]; then if [ "x${COMPUTE_TYPE}" != "xmaven" ]; then mkdir "${WEBROOT}/${PROJECT_NAME}/"; else [ -d "${WEBROOT}/${OLD_PROJECT_NAME}/" ] && mkdir "${WEBROOT}/${PROJECT_NAME}/"; fi fi [ -d "${WEBROOT}/${PROJECT_NAME}/" ] && [ -d "${WEBROOT}/${OLD_PROJECT_NAME}/" ] && { renameContext $PROJECT_NAME $OLD_PROJECT_NAME ; } [ "x${PROJECT_NAME}" != "xROOT" ] && ATOMIC_DEPLOY="false"; } renameHooks $PROJECT_NAME $OLD_PROJECT_NAME; if [ "$changeUrlresult" -eq 0 ]; then writeProjectConfig ; writeProjectresult=$?; else writeProjectresult=-1; fi if [ "$writeProjectresult" -eq 0 -a "$changeUrlresult" -eq 0 ]; then if [ "x$OLD_PROJECT_NAME" != "x$PROJECT_NAME" -a -f "${VCS_CONFIG_DIR}/${OLD_PROJECT_NAME}.properties" ];then rm -f "${VCS_CONFIG_DIR}/${OLD_PROJECT_NAME}.properties"; fi VAL="project_name=>${PROJECT_NAME} vcs_type=>${VCS_TYPE} url=>${URL} login=>${LOGIN} branch=>${BRANCH} resolveconflict=>${GIT_AUTORESOLVE_CONFLICT}"; if [ ! -z "$CONTEXT" -a ! -z "$ENVIRONMENT" ] ; then VAL=$VAL" environment=>${ENVIRONMENT} context=>${CONTEXT} autoupdate=>${AUTOUPDATE} interval=>${UPDATE_INTERVAL}" ; fi if [ ! -z "$AUTHORIZATION_KEY_VAL" ] ; then hash=`echo $AUTHORIZATION_KEY_VAL | md5sum | $AWK '{print $1}'`; VAL=$VAL" hash=>$hash"; fi writeJSONResponseOut "result=>0" "message=>Project edited successfully" ${VAL} ; else writeJSONResponseErr "result=>4017" "message=>Project edit failed" return 1 fi } function describeUpdate(){ echo "Update project"; }