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."
 
    ;;
 
esac

this file has been updated overtime, but this focusses on the pure functionality