Deployment Manager
infrastructure automation linux
This deployment manager is a bash script written to be highly configurable and deploy all the applications at once, it makes use of the email id and use the gitlab Gitlab access token to authenticate with the Gitlab server, you can dynamically add new and remove projects on the fly, the main focus to 0 downtime maximum flexibility for the developer, you can even configure which branch needs to be used for the builds, thus removing the necessity to checkout the different branches as now this is done automatically.
probably one of the best things i have done in the past few months after the auto docker builds.
The code below is the deployment manager.
#!/usr/bin/env bash
# The Deployment Manager
# Organization: Nebulogic Technologies
# Author: Kalyan Mudumby (@theinhumaneme / kalyan.mudumby@nebulogic.com)
# Date: 20-02-2024
# Maintainer: Kalyan Mudumby
# Project Fortwayne 311
#------------- CONFIGURABLE DATA -----
# ------- CRM -----------------------
SMART_CRM_GITLAB_URL="smart/crm2"
#SMART_CRM_REPO_BRANCH=""
# ------- ICE -----------------------
SMART_ICE_GITLAB_URL="smart/ice"
#SMART_ICE_REPO_BRANCH="new-hyd-dev-branch"
# ------- CITIZEN_SERVICES -----------------------
CITIZEN_SERVICES_GITLAB_URL="smart311/311services"
#CITIZEN_SERVICES_REPO_BRANCH="rel-v1.0-FAQ"
# ------- AGENT PORTAL -----------------------
AGENT_PORTAL_GITLAB_URL="smart311/agent-Portal"
#AGENT_PORTAL_REPO_BRANCH="agentscript-checkbox"
# ------- CITIZEN_PORTAL -----------------------
CITIZEN_PORTAL_GITLAB_URL="smart311/customerportal"
#CITIZEN_PORTAL_REPO_BRANCH=""
#------- EVENT_HANDLER-----------------------
EVENT_HANDLER_GITLAB_URL="smart311/311eventhandler"
#EVENT_HANDLER_REPO_BRANCH=""
#------- MAIL_RECEIVER -----------------------
MAIL_RECEIVER_GITLAB_URL="smart311/311mailreceiver"
#MAIL_RECEIVER_REPO_BRANCH=""
# CHAT BUDDY
CHATBUDDY_GITLAB_URL="kalyan.mudumby/conversation-bot"
# SMART REPORTER
SMART_REPORTER_GITLAB_URL="smart311/smartreporter"
projects=(
"SMART_CRM"
"SMART_ICE"
"AGENT_PORTAL"
"CITIZEN_PORTAL"
"CITIZEN_SERVICES"
"EVENT_HANDLER"
"MAIL_RECEIVER"
"CHATBUDDY"
"SMART_REPORTER"
)
options=(
"Build and Deploy"
"Restart the Application"
"Stop the Application"
)
# BEFORE YOU PROCEED TO TOUCH ANY OF THE CODE BELOW MAKE SURE YOU KNOW WHAT YOU ARE DOING
# EVEN A SMALL CHANGE CAN BREAK THE DEPLOYMENT MANAGER
# ----- NON CONFIGURABLE STUFF --------
PROJECT_ROOT_DIR="/home/ubuntu/FORTWAYNE-311"
GITLAB_HOST_DOMAIN="gitlab.nebulogic.com"
SMART_CRM_DIRECTORY_NAME="SMART_CRM"
SMART_ICE_DIRECTORY_NAME="SMART_ICE"
CITIZEN_SERVICES_DIRECTORY_NAME="CITIZEN_SERVICES"
AGENT_PORTAL_DIRECTORY_NAME="AGENT_PORTAL"
CITIZEN_PORTAL_DIRECTORY_NAME="CITIZEN_PORTAL"
EVENT_HANDLER_DIRECTORY_NAME="EVENT_HANDLER"
MAIL_RECEIVER_DIRECTORY_NAME="MAIL_RECEIVER"
CHATBUDDY_DIRECTORY_NAME="CHATBUDDY"
SMART_REPORTER_DIRECTORY_NAME="SMART_REPORTER"
# ------ PROJECT VARIABLES ---------
CLIENT_NAME="CITY OF FORTWAYNE"
DEPLOY_USER=$GITLAB_USERNAME
DEPLOY_PASSWORD=$GITLAB_PASSWORD
# ---- HELPER FUNCTIONS ------------
# Provide the enter to exit feature
wait_exit() {
echo ""
read -p "Press enter to exit..."
exit $1
}
# Function to check if a value is a number
is_number() {
[[ "$1" =~ ^[0-9]+$ ]]
}
docker_build_deploy(){
cd ${2}
choose_branch ${1}
git checkout $WORKING_BRANCH
COMPOSE_FILE=$PROJECT_ROOT_DIR/${1}.yaml
docker-compose -f $COMPOSE_FILE build
# Check the exit status of the build command
if [ $? -eq 0 ]; then
echo ""
echo "Docker build successful"
echo "Spinning up containers"
docker-compose -f $COMPOSE_FILE up -d
if [ $? -eq 0 ]; then
echo "Application is up and running"
else
echo ""
echo "Unable to bring up containers. Exiting script"
wait_exit
fi
else
echo ""
echo "Error: Docker build failed. Exiting script."
wait_exit
fi
}
docker_restart(){
COMPOSE_FILE=$PROJECT_ROOT_DIR/${1}.yaml
docker-compose -f $COMPOSE_FILE restart
# Check the exit status of the build command
if [ $? -eq 0 ]; then
echo ""
echo "Application Restarted"
else
echo ""
echo "Error: No Containers to restart. Exiting script."
wait_exit
fi
}
docker_stop(){
COMPOSE_FILE=$PROJECT_ROOT_DIR/${1}.yaml
docker-compose -f $COMPOSE_FILE stop
# Check the exit status of the build command
if [ $? -eq 0 ]; then
echo ""
echo "Containers stopped Sucessfully"
else
echo ""
echo "Error: No Containers to stop. Exiting script."
wait_exit
fi
}
WORKING_BRANCH=""
choose_branch() {
branches=()
# Read the output of git branch -r directly into the branches array
while IFS= read -r line; do
trimmed_branch="${line#*origin/}"
if [[ "$trimmed_branch" != "HEAD -> origin/main" ]]; then
branches+=("$trimmed_branch")
fi
done < <(git branch -r)
echo "Choose one of the Available Branches for ${1}"
echo "Available Branches:"
echo ""
for i in "${!branches[@]}"; do
echo "$((i+1)). ${branches[i]}"
done
echo ""
while true; do
read -p "Choose a Branch: (Enter a Number)" selected_branch
if [[ $selected_branch =~ ^[0-9]+$ ]]; then
index=$((selected_branch - 1))
if [ "$index" -ge 0 ] && [ "$index" -lt "${#branches[@]}" ]; then
selected_branch="${branches[index]}"
screen_header
echo ""
echo "Branch Selected - $selected_branch"
break
else
echo "Invalid Branch Number. Please try again."
fi
else
echo "Invalid input. Please enter a number."
fi
done
WORKING_BRANCH=$selected_branch
}
pull_repo(){
REPO_PATH="${1}_GITLAB_URL"
PROJECT_PATH="${1}_DIRECTORY_NAME"
# WORKING_BRANCH="${1}_REPO_BRANCH"
FQRN="https://$DEPLOY_USER:$DEPLOY_PASSWORD@$GITLAB_HOST_DOMAIN/${!REPO_PATH}"
# branch_selected= $(choose_branch ${!PROJECT_PATH})
# echo branch_selected
# echo
# if [ -n "${!WORKING_BRANCH}" ]; then
# cd $PROJECT_ROOT_DIR/${!PROJECT_PATH}
# git pull
# git checkout ${!WORKING_BRANCH}
# echo "branch set to ${!WORKING_BRANCH}"
# else
# cd $PROJECT_ROOT_DIR/${!PROJECT_PATH}
# value=$(git remote show origin | grep "HEAD" | awk '{print $NF}')
# git pull
# git checkout $value
# fi
echo $PROJECT_ROOT_DIR/${!PROJECT_PATH}
cd $PROJECT_ROOT_DIR/${!PROJECT_PATH} && git pull --all
}
clone_repo(){
REPO_PATH="${1}_GITLAB_URL"
PROJECT_PATH="${1}_DIRECTORY_NAME"
# WORKING_BRANCH="${1}_REPO_BRANCH"
FQRN="https://$DEPLOY_USER:$DEPLOY_PASSWORD@$GITLAB_HOST_DOMAIN/${!REPO_PATH}"
echo
# if [ -n "${!WORKING_BRANCH}" ]; then
# echo "branch set to ${!WORKING_BRANCH}"
# git clone $FQRN $PROJECT_ROOT_DIR/${!PROJECT_PATH}
# echo $PROJECT_ROOT_DIR/${!PROJECT_PATH}
# cd $PROJECT_ROOT_DIR/${!PROJECT_PATH}
# git checkout ${!WORKING_BRANCH}
# else
# git clone $FQRN $PROJECT_ROOT_DIR/${!PROJECT_PATH}
# fi
git clone $FQRN $PROJECT_ROOT_DIR/${!PROJECT_PATH}
}
check_repo_exists(){
if [ -d $1/$2 ] ; then
echo "repo exists"
echo "pulling latest changes"
pull_repo $2
else
echo ""
echo "Repository not found on this machine, you have to clone the repo to proceed"
echo ""
while true; do
echo ""
read -p "Would you like to clone $2 [yY/nN]" clone_repo_answer
if [ $clone_repo_answer == "y" ] || [ $clone_repo_answer == "Y" ]; then
echo "You selected Yes"
clone_repo "$2"
break
elif [ $clone_repo_answer == "n" ] || [ $clone_repo_answer == "N" ]; then
echo "You selected No"
break
else
echo "Invalid Option Selected"
fi
done
fi
}
screen_header() {
clear
echo ""
echo "███████╗ ██████╗ ██████╗ ████████╗██╗ ██╗ █████╗ ██╗ ██╗███╗ ██╗███████╗ ██████╗ ██╗ ██╗"
echo "██╔════╝██╔═══██╗██╔══██╗╚══██╔══╝██║ ██║██╔══██╗╚██╗ ██╔╝████╗ ██║██╔════╝ ╚════██╗ ███║ ███║"
echo "█████╗ ██║ ██║██████╔╝ ██║ ██║ █╗ ██║███████║ ╚████╔╝ ██╔██╗ ██║█████╗ █████╔╝ ╚██║ ╚██║"
echo "██╔══╝ ██║ ██║██╔══██╗ ██║ ██║███╗██║██╔══██║ ╚██╔╝ ██║╚██╗██║██╔══╝ ╚═══██╗ ██║ ██║"
echo "██║ ╚██████╔╝██║ ██║ ██║ ╚███╔███╔╝██║ ██║ ██║ ██║ ╚████║███████╗ ██████╔╝ ██║ ██║"
echo "╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚══╝╚══╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═══╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝"
echo ""
echo "---------- DEPLOYMENT MANAGER ---------"
echo "---------- NEBULOGIC TECHNOLOGIES ---------"
echo "---------- AUTHOR - Kalyan Mudumby ---------"
echo ""
}
screen_header
echo "Available Projects:"
echo ""
for i in "${!projects[@]}"; do
echo "$((i+1)). ${projects[i]}"
done
echo ""
while true; do
read -p "Choose a Project: (Enter a Number)" user_project_input
if is_number "$user_project_input"; then
index=$((user_project_input - 1))
if [ "$index" -ge 0 ] && [ "$index" -lt "${#projects[@]}" ]; then
selected_project="${projects[index]}"
screen_header
echo ""
echo "Project Selected - $selected_project"
break
else
echo "Invalid project number. Please try again."
fi
else
echo "Invalid input. Please enter a number."
fi
done
echo ""
for i in "${!options[@]}"; do
echo "$((i+1)). ${options[i]}"
done
echo ""
while true; do
read -p "Choose a Option: (Enter a Number)" user_option_input
if is_number "$user_project_input"; then
index=$((user_option_input - 1))
if [ "$index" -ge 0 ] && [ "$index" -lt "${#options[@]}" ]; then
selected_option="${options[index]}"
screen_header
echo ""
echo "You have chosen $selected_option"
break
else
echo "Invalid Option number. Please try again."
fi
else
echo "Invalid input. Please enter a number."
fi
done
echo $PROJECT_ROOT_DIR/"$selected_project"
case $user_option_input in
1)
echo "You chose: Build and Deploy"
check_repo_exists $PROJECT_ROOT_DIR "$selected_project"
docker_build_deploy $selected_project $PROJECT_ROOT_DIR/"$selected_project"
;;
2)
echo "You chose: Restart the Application"
docker_restart $selected_project
;;
3)
echo "You chose: Stop the Application"
docker_stop $selected_project
;;
*)
echo "Invalid option. Please select a valid option."
;;
esacthis file has been updated overtime, but this focusses on the pure functionality