#!/bin/bash -e ################### # ARRAY UTILITIES # ################### function arrayToParameters() { local -r array=("${@}") local -r string="$(printf "'%s' " "${array[@]}")" echo "${string:0:${#string} - 1}" } function arrayToString() { local -r array=("${@}") arrayToStringWithDelimiter ',' "${array[@]}" } function arrayToStringWithDelimiter() { local -r delimiter="${1}" local -r list=("${@:2}") local -r string="$(printf "%s${delimiter}" "${list[@]}")" echo "${string:0:${#string} - ${#delimiter}}" } function excludeElementFromArray() { local -r element="${1}" local array=("${@:2}") local i=0 for ((i = 0; i < ${#array[@]}; i = i + 1)) do if [[ "${array[i]}" = "${element}" ]] then unset array['${i}'] fi done echo "${array[@]}" } function isElementInArray() { local -r element="${1}" local -r array=("${@:2}") local walker='' for walker in "${array[@]}" do [[ "${walker}" = "${element}" ]] && echo 'true' && return 0 done echo 'false' && return 1 } function sortUniqArray() { local -r array=("${@}") trimString "$(tr ' ' '\n' <<< "${array[@]}" | sort -u | tr '\n' ' ')" } ##################### # COMPILE UTILITIES # ##################### function compileAndInstallFromSource() { local -r downloadURL="${1}" local -r installFolderPath="${2}" local -r installFileOrFolderBinPath="${3}" local -r user="${4}" initializeFolder "${installFolderPath}" local -r currentWorkingDirectory="$(pwd)" local -r tempFolder="$(getTemporaryFolder)" unzipRemoteFile "${downloadURL}" "${tempFolder}" cd "${tempFolder}" "${tempFolder}/configure" --prefix="${installFolderPath}" make make install chown -R "${user}:$(getUserGroupName "${user}")" "${installFolderPath}" symlinkUsrBin "${installFileOrFolderBinPath}" cd "${currentWorkingDirectory}" rm -f -r "${tempFolder}" } ####################### # DATE TIME UTILITIES # ####################### function convertISO8601ToSeconds() { local -r time="${1}" if [[ "$(isMacOperatingSystem)" = 'true' ]] then date -j -u -f '%FT%T' "$(awk -F '.' '{ print $1 }' <<< "${time}" | tr -d 'Z')" +'%s' elif [[ "$(isAmazonLinuxDistributor)" = 'true' || "$(isCentOSDistributor)" = 'true' || "$(isRedHatDistributor)" = 'true' || "$(isUbuntuDistributor)" = 'true' ]] then date -d "${time}" +'%s' else fatal '\nFATAL : only support Amazon-Linux, CentOS, Mac, RedHat, or Ubuntu OS' fi } function getISO8601DateTimeNow() { date -u +'%Y-%m-%dT%H:%M:%SZ' } function getUTCNowInSeconds() { date -u +'%s' } function secondsToReadableTime() { local -r time="${1}" local -r day="$((time / 60 / 60 / 24))" local -r hour="$((time / 60 / 60 % 24))" local -r minute="$((time / 60 % 60))" local -r second="$((time % 60))" if [[ "${day}" = '0' ]] then printf '%02d:%02d:%02d' "${hour}" "${minute}" "${second}" elif [[ "${day}" = '1' ]] then printf '%d day and %02d:%02d:%02d' "${day}" "${hour}" "${minute}" "${second}" else printf '%d days and %02d:%02d:%02d' "${day}" "${hour}" "${minute}" "${second}" fi } ######################## # FILE LOCAL UTILITIES # ######################## function appendToFileIfNotFound() { local -r file="${1}" local -r pattern="${2}" local -r string="${3}" local -r patternAsRegex="${4}" local -r stringAsRegex="${5}" local -r addNewLine="${6}" # Validate Inputs checkExistFile "${file}" checkNonEmptyString "${pattern}" 'undefined pattern' checkNonEmptyString "${string}" 'undefined string' checkTrueFalseString "${patternAsRegex}" checkTrueFalseString "${stringAsRegex}" if [[ "${stringAsRegex}" = 'false' ]] then checkTrueFalseString "${addNewLine}" fi # Append String if [[ "${patternAsRegex}" = 'true' ]] then local -r found="$(grep -E -o "${pattern}" "${file}")" else local -r found="$(grep -F -o "${pattern}" "${file}")" fi if [[ "$(isEmptyString "${found}")" = 'true' ]] then if [[ "${stringAsRegex}" = 'true' ]] then echo -e "${string}" >> "${file}" else if [[ "${addNewLine}" = 'true' ]] then echo >> "${file}" fi echo "${string}" >> "${file}" fi fi } function checkExistFile() { local -r file="${1}" local -r errorMessage="${2}" if [[ "${file}" = '' || ! -f "${file}" ]] then if [[ "$(isEmptyString "${errorMessage}")" = 'true' ]] then fatal "\nFATAL : file '${file}' not found" fi fatal "\nFATAL : ${errorMessage}" fi } function checkExistFolder() { local -r folder="${1}" local -r errorMessage="${2}" if [[ "${folder}" = '' || ! -d "${folder}" ]] then if [[ "$(isEmptyString "${errorMessage}")" = 'true' ]] then fatal "\nFATAL : folder '${folder}' not found" fi fatal "\nFATAL : ${errorMessage}" fi } function checkValidJSONContent() { local -r content="${1}" if [[ "$(isValidJSONContent "${content}")" = 'false' ]] then fatal '\nFATAL : invalid JSON' fi } function checkValidJSONFile() { local -r file="${1}" if [[ "$(isValidJSONFile "${file}")" = 'false' ]] then fatal "\nFATAL : invalid JSON file '${file}'" fi } function cleanUpSystemFolders() { header 'CLEANING UP SYSTEM FOLDERS' local -r folders=( '/tmp' '/var/tmp' ) local folder='' for folder in "${folders[@]}" do echo "Cleaning up folder '${folder}'" emptyFolder "${folder}" done } function copyFolderContent() { local -r sourceFolder="${1}" local -r destinationFolder="${2}" checkExistFolder "${sourceFolder}" checkExistFolder "${destinationFolder}" find "${sourceFolder}" \ -mindepth 1 \ -maxdepth 1 \ -exec cp -p -r '{}' "${destinationFolder}" \; } function createAbsoluteUsrBin() { local -r binFileName="${1}" local -r sourceFilePath="${2}" checkExistFile "${sourceFilePath}" mkdir -p '/usr/bin' printf "#!/bin/bash -e\n\n'%s' \"\${@}\"" "${sourceFilePath}" > "/usr/bin/${binFileName}" chmod 755 "/usr/bin/${binFileName}" } function createFileFromTemplate() { local -r sourceFile="${1}" local -r destinationFile="${2}" local -r oldNewData=("${@:3}") checkExistFile "${sourceFile}" checkExistFolder "$(dirname "${destinationFile}")" local content='' content="$(cat "${sourceFile}")" local i=0 for ((i = 0; i < ${#oldNewData[@]}; i = i + 2)) do content="$(replaceString "${content}" "${oldNewData[${i}]}" "${oldNewData[${i} + 1]}")" done echo "${content}" > "${destinationFile}" } function createInitFileFromTemplate() { local -r serviceName="${1}" local -r templateFolderPath="${2}" local -r initConfigDataFromTemplate=("${@:3}") createFileFromTemplate \ "${templateFolderPath}/${serviceName}.service.systemd" \ "/etc/systemd/system/${serviceName}.service" \ "${initConfigDataFromTemplate[@]}" } function deleteOldLogs() { local logFolderPaths=("${@}") header 'DELETING OLD LOGS' # Default Log Folder Path if [[ "${#logFolderPaths[@]}" -lt '1' ]] then logFolderPaths+=('/var/log') fi # Walk Each Log Folder Path local i=0 for ((i = 0; i < ${#logFolderPaths[@]}; i = i + 1)) do checkExistFolder "${logFolderPaths[i]}" find \ -L \ "${logFolderPaths[i]}" \ -type f \ \( \ -regex '.*-[0-9]+' -o \ -regex '.*\.[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\.log' -o \ -regex '.*\.[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\.txt' -o \ -regex '.*\.[0-9]+' -o \ -regex '.*\.[0-9]+\.log' -o \ -regex '.*\.gz' -o \ -regex '.*\.log\.[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]T[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]' -o \ -regex '.*\.old' -o \ -regex '.*\.xz' \ \) \ -delete \ -print done } function emptyFolder() { local -r folder="${1}" checkExistFolder "${folder}" find "${folder}" \ -mindepth 1 \ -delete } function getFileExtension() { local -r string="${1}" local -r fullFileName="$(basename "${string}")" echo "${fullFileName##*.}" } function getFileName() { local -r string="${1}" local -r fullFileName="$(basename "${string}")" echo "${fullFileName%.*}" } function getTemporaryFile() { local extension="${1}" if [[ "$(isEmptyString "${extension}")" = 'false' && "$(grep -i -o "^." <<< "${extension}")" != '.' ]] then extension=".${extension}" fi mktemp "$(getTemporaryFolderRoot)/$(date +'%Y%m%d-%H%M%S')-XXXXXXXXXX${extension}" } function getTemporaryFolder() { mktemp -d "$(getTemporaryFolderRoot)/$(date +'%Y%m%d-%H%M%S')-XXXXXXXXXX" } function getTemporaryFolderRoot() { local temporaryFolder='/tmp' if [[ "$(isEmptyString "${TMPDIR}")" = 'false' ]] then temporaryFolder="$(formatPath "${TMPDIR}")" fi echo "${temporaryFolder}" } function initializeFolder() { local -r folder="${1}" if [[ -d "${folder}" ]] then emptyFolder "${folder}" else mkdir -p "${folder}" fi } function isValidJSONContent() { local -r content="${1}" if ( python -m 'json.tool' <<< "${content}" &> '/dev/null' ) then echo 'true' && return 0 fi echo 'false' && return 1 } function isValidJSONFile() { local -r file="${1}" checkExistFile "${file}" isValidJSONContent "$(cat "${file}")" } function moveFolderContent() { local -r sourceFolder="${1}" local -r destinationFolder="${2}" checkExistFolder "${sourceFolder}" checkExistFolder "${destinationFolder}" find "${sourceFolder}" \ -mindepth 1 \ -maxdepth 1 \ -exec mv '{}' "${destinationFolder}" \; } function redirectOutputToLogFile() { local -r logFile="${1}" mkdir -p "$(dirname "${logFile}")" exec > >(tee -a "${logFile}") 2>&1 } function resetFolderPermission() { local -r folderPath="${1}" local -r userLogin="${2}" local -r groupName="${3}" checkExistFolder "${folderPath}" checkExistUserLogin "${userLogin}" checkExistGroupName "${groupName}" header "RESETTING FOLDER PERMISSION ${folderPath}" chown -R "${userLogin}:${groupName}" "${folderPath}" find "${folderPath}" \ -type d \ \( \ -not -path "*/.git" -a \ -not -path "*/.git/*" \ \) \ -exec chmod 700 '{}' \; \ -print find "${folderPath}" \ -type f \ \( \ -not -path "*/.git" -a \ -not -path "*/.git/*" \ \) \ -exec chmod 600 '{}' \; \ -print } function resetLogs() { local logFolderPaths=("${@}") # Default Log Folder Path if [[ "${#logFolderPaths[@]}" -lt '1' ]] then logFolderPaths+=('/var/log') fi # Delete Old Logs deleteOldLogs "${logFolderPaths[@]}" # Reset Logs header 'RESETTING LOGS' local i=0 for ((i = 0; i < ${#logFolderPaths[@]}; i = i + 1)) do checkExistFolder "${logFolderPaths[i]}" find "${logFolderPaths[i]}" \ -type f \ -exec cp -f '/dev/null' '{}' \; \ -print done } function symlinkListUsrBin() { local -r sourceFilePaths=("${@}") local sourceFilePath='' for sourceFilePath in "${sourceFilePaths[@]}" do chmod 755 "${sourceFilePath}" rm -f -r "/usr/bin/$(basename "${sourceFilePath}")" ln -f -s "${sourceFilePath}" "/usr/bin/$(basename "${sourceFilePath}")" done } function symlinkUsrBin() { local -r sourceBinFileOrFolder="${1}" if [[ "$(isMacOperatingSystem)" = 'true' ]] then mkdir -p '/usr/bin' if [[ -d "${sourceBinFileOrFolder}" ]] then find "${sourceBinFileOrFolder}" -maxdepth 1 \( -type f -o -type l \) -perm -u+x -exec bash -c -e ' for file do fileType="$(stat -f "%HT" "${file}")" if [[ "${fileType}" = "Regular File" ]] then ln -f -s "${file}" "/usr/bin/$(basename "${file}")" elif [[ "${fileType}" = "Symbolic Link" ]] then cd "$(dirname "${file}")" if [[ -f "$(readlink "${file}")" ]] then ln -f -s "${file}" "/usr/bin/$(basename "${file}")" fi fi done' bash '{}' \; elif [[ -f "${sourceBinFileOrFolder}" ]] then ln -f -s "${sourceBinFileOrFolder}" "/usr/bin/$(basename "${sourceBinFileOrFolder}")" else fatal "\nFATAL : '${sourceBinFileOrFolder}' is not directory or file" fi elif [[ "$(isAmazonLinuxDistributor)" = 'true' || "$(isCentOSDistributor)" = 'true' || "$(isRedHatDistributor)" = 'true' || "$(isUbuntuDistributor)" = 'true' ]] then mkdir -p '/usr/bin' if [[ -d "${sourceBinFileOrFolder}" ]] then find "${sourceBinFileOrFolder}" -maxdepth 1 -xtype f -perm -u+x -exec bash -c -e ' for file do ln -f -s "${file}" "/usr/bin/$(basename "${file}")" done' bash '{}' \; elif [[ -f "${sourceBinFileOrFolder}" ]] then ln -f -s "${sourceBinFileOrFolder}" "/usr/bin/$(basename "${sourceBinFileOrFolder}")" else fatal "\nFATAL : '${sourceBinFileOrFolder}' is not directory or file" fi else fatal '\nFATAL : only support Amazon-Linux, CentOS, Mac, RedHat, or Ubuntu OS' fi } function trimFile() { local -r filePath="${1}" checkExistFile "${filePath}" printf '%s' "$(< "${filePath}")" > "${filePath}" } ######################### # FILE REMOTE UTILITIES # ######################### function checkExistURL() { local -r url="${1}" if [[ "$(existURL "${url}")" = 'false' ]] then fatal "\nFATAL : url '${url}' not found" fi } function downloadFile() { local -r url="${1}" local -r destinationFile="${2}" local overwrite="${3}" checkExistURL "${url}" # Check Overwrite if [[ "$(isEmptyString "${overwrite}")" = 'true' ]] then overwrite='false' fi checkTrueFalseString "${overwrite}" # Validate if [[ -f "${destinationFile}" ]] then if [[ "${overwrite}" = 'false' ]] then fatal "\nFATAL : file '${destinationFile}' found" fi rm -f "${destinationFile}" elif [[ -e "${destinationFile}" ]] then fatal "\nFATAL : file '${destinationFile}' already exists" fi # Download debug "\nDownloading '${url}' to '${destinationFile}'\n" curl -L "${url}" -o "${destinationFile}" --retry 12 --retry-delay 5 } function existURL() { local -r url="${1}" # Install Curl installCURLCommand > '/dev/null' # Check URL if ( curl -f --head -L "${url}" -o '/dev/null' -s --retry 12 --retry-delay 5 || curl -f -L "${url}" -o '/dev/null' -r 0-0 -s --retry 12 --retry-delay 5 ) then echo 'true' && return 0 fi echo 'false' && return 1 } function getRemoteFileContent() { local -r url="${1}" checkExistURL "${url}" curl -s -X 'GET' -L "${url}" --retry 12 --retry-delay 5 } function unzipRemoteFile() { local -r downloadURL="${1}" local -r installFolder="${2}" local extension="${3}" # Install Curl installCURLCommand # Validate URL checkExistURL "${downloadURL}" # Find Extension local exExtension='' if [[ "$(isEmptyString "${extension}")" = 'true' ]] then extension="$(getFileExtension "${downloadURL}")" exExtension="$(rev <<< "${downloadURL}" | cut -d '.' -f 1-2 | rev)" fi # Unzip if [[ "$(grep -i '^tgz$' <<< "${extension}")" != '' || "$(grep -i '^tar\.gz$' <<< "${extension}")" != '' || "$(grep -i '^tar\.gz$' <<< "${exExtension}")" != '' ]] then debug "\nDownloading '${downloadURL}'\n" curl -L "${downloadURL}" --retry 12 --retry-delay 5 | tar -C "${installFolder}" -x -z --strip 1 echo elif [[ "$(grep -i '^tar\.bz2$' <<< "${exExtension}")" != '' ]] then # Install BZip2 installBZip2Command # Unzip debug "\nDownloading '${downloadURL}'\n" curl -L "${downloadURL}" --retry 12 --retry-delay 5 | tar -C "${installFolder}" -j -x --strip 1 echo elif [[ "$(grep -i '^zip$' <<< "${extension}")" != '' ]] then # Install Unzip installUnzipCommand # Unzip if [[ "$(existCommand 'unzip')" = 'false' ]] then fatal 'FATAL : command unzip not found' fi local -r zipFile="${installFolder}/$(basename "${downloadURL}")" downloadFile "${downloadURL}" "${zipFile}" 'true' unzip -q "${zipFile}" -d "${installFolder}" rm -f "${zipFile}" echo else fatal "\nFATAL : file extension '${extension}' not supported" fi } ################# # GIT UTILITIES # ################# function getGitPrivateRepositorySSHURL() { local -r user="${1}" local -r token="${2}" local -r orgName="${3}" local -r gitURL="${4}" getGitUserRepositoryObjectKey "${user}" "${token}" 'ssh_url' 'private' "${orgName}" "${gitURL}" } function getGitPublicRepositorySSHURL() { local -r user="${1}" local -r token="${2}" local -r orgName="${3}" local -r gitURL="${4}" getGitUserRepositoryObjectKey "${user}" "${token}" 'ssh_url' 'public' "${orgName}" "${gitURL}" } function getGitRepositoryNameFromCloneURL() { local -r cloneURL="${1}" checkNonEmptyString "${cloneURL}" 'undefined clone url' if [[ "$(grep -F -o '@' <<< "${cloneURL}")" != '' ]] then awk -F '/' '{ print $2 }' <<< "${cloneURL}" | rev | cut -d '.' -f 2- | rev else awk -F '/' '{ print $5 }' <<< "${cloneURL}" | rev | cut -d '.' -f 2- | rev fi } function getGitUserName() { local -r user="${1}" local -r token="${2}" local gitURL="${3}" # Default Value if [[ "$(isEmptyString "${gitURL}")" = 'true' ]] then gitURL='https://api.github.com' fi # Validation checkNonEmptyString "${user}" 'undefined user' checkNonEmptyString "${token}" 'undefined token' # Get User Name curl \ -s \ -X 'GET' \ -u "${user}:${token}" \ -L "${gitURL}/user" \ --retry 12 \ --retry-delay 5 | jq \ --compact-output \ --raw-output \ --sort-keys \ '.["name"] // empty' } function getGitUserPrimaryEmail() { local -r user="${1}" local -r token="${2}" local gitURL="${3}" # Default Values if [[ "$(isEmptyString "${gitURL}")" = 'true' ]] then gitURL='https://api.github.com' fi # Validation checkNonEmptyString "${user}" 'undefined user' checkNonEmptyString "${token}" 'undefined token' # Pagination local page=1 local exitCount=0 for ((page = 1; page > exitCount; page = page + 1)) do local emails='' emails="$( curl \ -s \ -X 'GET' \ -u "${user}:${token}" \ -L "${gitURL}/user/emails?page=${page}&per_page=100" \ --retry 12 \ --retry-delay 5 | jq \ --compact-output \ --raw-output \ --sort-keys \ '.[] // empty' \ )" local primaryEmail='' primaryEmail="$( jq \ --compact-output \ --raw-output \ --sort-keys \ 'select(.["primary"] == true) | .["email"] // empty' \ <<< "${emails}" )" if [[ "$(isEmptyString "${primaryEmail}")" = 'false' || "$(isEmptyString "${emails}")" = 'true' ]] then echo "${primaryEmail}" exitCount="$((page + 1))" fi done } function getGitUserRepositoryObjectKey() { local -r user="${1}" local -r token="${2}" local -r objectKey="${3}" local -r kind="${4}" local -r orgName="${5}" local gitURL="${6}" # Default Value if [[ "$(isEmptyString "${gitURL}")" = 'true' ]] then gitURL='https://api.github.com' fi # Validation checkNonEmptyString "${user}" 'undefined user' checkNonEmptyString "${token}" 'undefined token' checkNonEmptyString "${objectKey}" 'undefined object key' checkNonEmptyString "${gitURL}" 'undefined git url' # Pagination local results='' local page=1 local exitCount=0 for ((page = 1; page > exitCount; page = page + 1)) do # User or Organization if [[ "$(isEmptyString "${orgName}")" = 'true' ]] then local targetURL="${gitURL}/user/repos?affiliation=owner&page=${page}&per_page=100&visibility=${kind}" else local targetURL="${gitURL}/orgs/${orgName}/repos?page=${page}&per_page=100&type=${kind}" fi # Retrieve Objects local currentObjectValue='' currentObjectValue="$( curl \ -s \ -X 'GET' \ -u "${user}:${token}" \ -L "${targetURL}" \ --retry 12 \ --retry-delay 5 | jq \ --arg jqObjectKey "${objectKey}" \ --compact-output \ --raw-output \ --sort-keys \ '.[] | .[$jqObjectKey] // empty' )" if [[ "$(isEmptyString "${currentObjectValue}")" = 'true' ]] then exitCount="$((page + 1))" elif [[ "${page}" = '1' ]] then results="$(printf '%s' "${currentObjectValue}")" else results="$(printf '%s\n%s' "${results}" "${currentObjectValue}")" fi done # Return Results echo "${results}" | sort -f } ##################### # INSTALL UTILITIES # ##################### function installPortableBinary() { local -r appTitleName="${1}" local -r downloadURL="${2}" local -r installFolderPath="${3}" local -r binarySubPaths=($(sortUniqArray "$(replaceString "${4}" ',' ' ')")) local -r versionOption="${5}" local -r remoteUnzip="${6}" checkNonEmptyString "${appTitleName}" 'undefined app title name' checkNonEmptyString "${versionOption}" 'undefined version option' checkTrueFalseString "${remoteUnzip}" if [[ "${#binarySubPaths[@]}" -lt '1' ]] then fatal '\nFATAL : undefined binary sub paths' fi header "INSTALLING ${appTitleName}" checkRequireLinuxSystem checkRequireRootUser umask '0022' initializeFolder "${installFolderPath}" if [[ "${remoteUnzip}" = 'true' ]] then if [[ "$(getFileExtension "${downloadURL}")" = 'sh' ]] then curl -s -L "${downloadURL}" --retry 12 --retry-delay 5 | bash -e else unzipRemoteFile "${downloadURL}" "${installFolderPath}" fi printf '%s\n\nexport PATH="%s/%s:${PATH}"' \ '#!/bin/sh -e' \ "${installFolderPath}" \ "$(dirname "${binarySubPaths[0]}")" \ > "/etc/profile.d/$(basename "${installFolderPath}").sh" chmod 644 "/etc/profile.d/$(basename "${installFolderPath}").sh" else downloadFile "${downloadURL}" "${installFolderPath}/${binarySubPaths[0]}" 'true' fi chown -R "$(whoami):$(whoami)" "${installFolderPath}" local binarySubPath='' for binarySubPath in "${binarySubPaths[@]}" do symlinkListUsrBin "${installFolderPath}/${binarySubPath}" done displayVersion "$("/usr/bin/$(basename "${binarySubPaths[0]}")" "${versionOption}")" umask '0077' installCleanUp } ################# # MAC UTILITIES # ################# function clearMacAppExtendedAttributes() { local -r headerMessage="${1}" local -r applicationPaths=("${@:2}") checkRequireMacSystem if [[ "${#applicationPaths[@]}" -gt '0' ]] then header "${headerMessage}" fi local applicationPath='' for applicationPath in "${applicationPaths[@]}" do # Find Non-Default Apple App if [[ "$(ls -d -l -O "${applicationPath}" | grep -E '\s+restricted\s+')" = '' ]] then info "clearing extended attributes of '${applicationPath}'" xattr -c -r -s "${applicationPath}" fi done } function closeMacApplications() { local -r headerMessage="${1}" local -r applicationNames=("${@:2}") checkRequireMacSystem if [[ "${#applicationNames[@]}" -gt '0' ]] then header "${headerMessage}" fi local applicationName='' for applicationName in "${applicationNames[@]}" do applicationName="$(getFileName "${applicationName}")" if [[ "${applicationName}" != 'Terminal' ]] then local errorMessage='' errorMessage="$(osascript -e "tell application \"${applicationName}\" to quit" 2>&1)" if [[ "$(isEmptyString "${errorMessage}")" = 'true' || "$(grep -E -o '\(-128)$' <<< "${errorMessage}")" != '' ]] then info "closing '${applicationName}'" else error "${errorMessage}" fi fi done } function getMacCurrentUserICloudDriveFolderPath() { local -r iCloudFolderPath="$(getCurrentUserHomeFolder)/Library/Mobile Documents/com~apple~CloudDocs" if [[ -d "${iCloudFolderPath}" ]] then echo "${iCloudFolderPath}" else echo fi } function openMacApplications() { local -r headerMessage="${1}" local -r applicationNames=("${@:2}") checkRequireMacSystem if [[ "${#applicationNames[@]}" -gt '0' ]] then header "${headerMessage}" fi local applicationName='' for applicationName in "${applicationNames[@]}" do info "openning '${applicationName}'" osascript -e "tell application \"${applicationName}\" to activate" done } #################### # NUMBER UTILITIES # #################### function checkNaturalNumber() { local -r string="${1}" local -r errorMessage="${2}" if [[ "$(isNaturalNumber "${string}")" = 'false' ]] then if [[ "$(isEmptyString "${errorMessage}")" = 'true' ]] then fatal '\nFATAL : not natural number detected' fi fatal "\nFATAL : ${errorMessage}" fi } function checkPositiveInteger() { local -r string="${1}" local -r errorMessage="${2}" if [[ "$(isPositiveInteger "${string}")" = 'false' ]] then if [[ "$(isEmptyString "${errorMessage}")" = 'true' ]] then fatal '\nFATAL : not positive number detected' fi fatal "\nFATAL : ${errorMessage}" fi } function isNaturalNumber() { local -r string="${1}" if [[ "${string}" =~ ^[0-9]+$ ]] then echo 'true' && return 0 fi echo 'false' && return 1 } function isPositiveInteger() { local -r string="${1}" if [[ "${string}" =~ ^[1-9][0-9]*$ ]] then echo 'true' && return 0 fi echo 'false' && return 1 } ################ # OS UTILITIES # ################ function checkRequireLinuxSystem() { if [[ "$(isAmazonLinuxDistributor)" = 'false' && "$(isCentOSDistributor)" = 'false' && "$(isRedHatDistributor)" = 'false' && "$(isUbuntuDistributor)" = 'false' ]] then fatal '\nFATAL : only support Amazon-Linux, CentOS, RedHat, or Ubuntu OS' fi if [[ "$(is64BitSystem)" = 'false' ]] then fatal '\nFATAL : non x86_64 OS found' fi } function checkRequireMacSystem() { if [[ "$(isMacOperatingSystem)" = 'false' ]] then fatal '\nFATAL : only support Mac OS' fi if [[ "$(is64BitSystem)" = 'false' ]] then fatal '\nFATAL : non x86_64 OS found' fi } function getMachineDescription() { lsb_release -d -s } function getMachineRelease() { lsb_release -r -s } function is64BitSystem() { isMachineHardware 'x86_64' } function isAmazonLinuxDistributor() { isDistributor 'amzn' } function isCentOSDistributor() { isDistributor 'centos' } function isDistributor() { local -r distributor="${1}" local -r found="$(grep -F -i -o -s "${distributor}" '/proc/version')" if [[ "$(isEmptyString "${found}")" = 'true' ]] then echo 'false' && return 1 fi echo 'true' && return 0 } function isLinuxOperatingSystem() { isOperatingSystem 'Linux' } function isMachineHardware() { local -r machineHardware="$(escapeGrepSearchPattern "${1}")" local -r found="$(uname -m | grep -E -i -o "^${machineHardware}$")" if [[ "$(isEmptyString "${found}")" = 'true' ]] then echo 'false' && return 1 fi echo 'true' && return 0 } function isMacOperatingSystem() { isOperatingSystem 'Darwin' } function isOperatingSystem() { local -r operatingSystem="$(escapeGrepSearchPattern "${1}")" local -r found="$(uname -s | grep -E -i -o "^${operatingSystem}$")" if [[ "$(isEmptyString "${found}")" = 'true' ]] then echo 'false' && return 1 fi echo 'true' && return 0 } function isRedHatDistributor() { isDistributor 'redhat' } function isUbuntuDistributor() { isDistributor 'ubuntu' } ##################### # PACKAGE UTILITIES # ##################### function getLastAptGetUpdate() { if [[ "$(isUbuntuDistributor)" = 'true' ]] then local -r aptDate="$(stat -c %Y '/var/cache/apt')" local -r nowDate="$(date +'%s')" echo $((nowDate - aptDate)) fi } function installBuildEssential() { if [[ "$(isUbuntuDistributor)" = 'true' ]] then installPackages 'build-essential' elif [[ "$(isAmazonLinuxDistributor)" = 'true' || "$(isCentOSDistributor)" = 'true' || "$(isRedHatDistributor)" = 'true' ]] then installPackages 'gcc-c++' 'kernel-devel' 'make' else fatal '\nFATAL : only support Amazon-Linux, CentOS, RedHat, or Ubuntu OS' fi } function installBZip2Command() { local -r commandPackage=('bzip2' 'bzip2') installCommands "${commandPackage[@]}" } function installCleanUp() { header 'CLEANING UP INSTALLATION' if [[ "$(isUbuntuDistributor)" = 'true' ]] then DEBIAN_FRONTEND='noninteractive' apt-get --fix-missing -y -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold' autoremove DEBIAN_FRONTEND='noninteractive' apt-get --fix-missing -y -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold' clean DEBIAN_FRONTEND='noninteractive' apt-get --fix-missing -y -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold' autoclean elif [[ "$(isAmazonLinuxDistributor)" = 'true' || "$(isCentOSDistributor)" = 'true' || "$(isRedHatDistributor)" = 'true' ]] then yum clean all else fatal '\nFATAL : only support Amazon-Linux, CentOS, RedHat, or Ubuntu OS' fi } function installCommands() { local -r commandPackageData=("${@}") if [[ "$(isUbuntuDistributor)" = 'true' ]] then runAptGetUpdate '' fi local i=0 for ((i = 0; i < ${#commandPackageData[@]}; i = i + 2)) do local command="${commandPackageData[${i}]}" local package="${commandPackageData[${i} + 1]}" checkNonEmptyString "${command}" 'undefined command' checkNonEmptyString "${package}" 'undefined package' if [[ "$(existCommand "${command}")" = 'false' ]] then installPackages "${package}" fi done } function installCURLCommand() { local -r commandPackage=('curl' 'curl') installCommands "${commandPackage[@]}" } function installPackage() { local -r aptPackage="${1}" local -r rpmPackage="${2}" if [[ "$(isUbuntuDistributor)" = 'true' ]] then if [[ "$(isEmptyString "${aptPackage}")" = 'false' ]] then if [[ "$(isAptGetPackageInstall "${aptPackage}")" = 'true' ]] then debug "\nApt-Get Package '${aptPackage}' has already been installed" else echo -e "\033[1;35m\nInstalling Apt-Get Package '${aptPackage}'\033[0m" DEBIAN_FRONTEND='noninteractive' apt-get install "${aptPackage}" --fix-missing -y || (DEBIAN_FRONTEND='noninteractive' apt-get install --fix-missing --yes -f -y && DEBIAN_FRONTEND='noninteractive' apt-get install "${aptPackage}" --fix-missing -y) fi fi elif [[ "$(isAmazonLinuxDistributor)" = 'true' || "$(isCentOSDistributor)" = 'true' || "$(isRedHatDistributor)" = 'true' ]] then if [[ "$(isEmptyString "${rpmPackage}")" = 'false' ]] then yum install -y "${rpmPackage}" fi else fatal '\nFATAL : only support Amazon-Linux, CentOS, RedHat, or Ubuntu OS' fi } function installPackages() { local -r packages=("${@}") if [[ "$(isUbuntuDistributor)" = 'true' ]] then runAptGetUpdate '' fi local package='' for package in "${packages[@]}" do if [[ "$(isUbuntuDistributor)" = 'true' ]] then installPackage "${package}" elif [[ "$(isAmazonLinuxDistributor)" = 'true' || "$(isCentOSDistributor)" = 'true' || "$(isRedHatDistributor)" = 'true' ]] then installPackage '' "${package}" else fatal '\nFATAL : only support Amazon-Linux, CentOS, RedHat, or Ubuntu OS' fi done } function installPIPCommand() { local -r commandPackage=('pip' 'python-pip') installCommands "${commandPackage[@]}" } function installPIPPackage() { local -r package="${1}" if [[ "$(isPIPPackageInstall "${package}")" = 'true' ]] then debug "PIP Package '${package}' found" else echo -e "\033[1;35m\nInstalling PIP package '${package}'\033[0m" pip install "${package}" fi } function installUnzipCommand() { local -r commandPackage=('unzip' 'unzip') installCommands "${commandPackage[@]}" } function isAptGetPackageInstall() { local -r package="$(escapeGrepSearchPattern "${1}")" local -r found="$(dpkg --get-selections | grep -E -o "^${package}(:amd64)*\s+install$")" if [[ "$(isEmptyString "${found}")" = 'true' ]] then echo 'false' && return 1 fi echo 'true' && return 0 } function isPIPPackageInstall() { local -r package="$(escapeGrepSearchPattern "${1}")" # Install PIP installPIPCommand > '/dev/null' # Check Command if [[ "$(existCommand 'pip')" = 'false' ]] then fatal 'FATAL : command python-pip not found' fi local -r found="$(pip list | grep -E -o "^${package}\s+\(.*\)$")" if [[ "$(isEmptyString "${found}")" = 'true' ]] then echo 'false' && return 1 fi echo 'true' && return 0 } function runAptGetUpdate() { local updateInterval="${1}" if [[ "$(isUbuntuDistributor)" = 'true' ]] then local -r lastAptGetUpdate="$(getLastAptGetUpdate)" if [[ "$(isEmptyString "${updateInterval}")" = 'true' ]] then # Default To 24 hours updateInterval="$((24 * 60 * 60))" fi if [[ "${lastAptGetUpdate}" -gt "${updateInterval}" ]] then info 'apt-get update' apt-get update -m else local -r lastUpdate="$(date -u -d @"${lastAptGetUpdate}" +'%-Hh %-Mm %-Ss')" info "\nSkip apt-get update because its last run was '${lastUpdate}' ago" fi fi } function runUpgrade() { header 'UPGRADING SYSTEM' if [[ "$(isUbuntuDistributor)" = 'true' ]] then runAptGetUpdate '' info '\napt-get upgrade' DEBIAN_FRONTEND='noninteractive' apt-get --fix-missing -y -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold' upgrade info '\napt-get dist-upgrade' DEBIAN_FRONTEND='noninteractive' apt-get --fix-missing -y -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold' dist-upgrade info '\napt-get autoremove' DEBIAN_FRONTEND='noninteractive' apt-get --fix-missing -y -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold' autoremove info '\napt-get clean' DEBIAN_FRONTEND='noninteractive' apt-get --fix-missing -y -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold' clean info '\napt-get autoclean' DEBIAN_FRONTEND='noninteractive' apt-get --fix-missing -y -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold' autoclean elif [[ "$(isAmazonLinuxDistributor)" = 'true' || "$(isCentOSDistributor)" = 'true' || "$(isRedHatDistributor)" = 'true' ]] then yum -y --security update yum -y update --nogpgcheck --skip-broken fi } function upgradePIPPackage() { local -r package="${1}" if [[ "$(isPIPPackageInstall "${package}")" = 'true' ]] then echo -e "\033[1;35mUpgrading PIP package '${package}'\033[0m" pip install --upgrade "${package}" else debug "PIP Package '${package}' not found" fi } ##################### # SERVICE UTILITIES # ##################### function disableService() { local -r serviceName="${1}" checkNonEmptyString "${serviceName}" 'undefined service name' if [[ "$(existCommand 'systemctl')" = 'true' ]] then header "DISABLE SYSTEMD ${serviceName}" systemctl daemon-reload systemctl disable "${serviceName}" systemctl stop "${serviceName}" || true else header "DISABLE SERVICE ${serviceName}" chkconfig "${serviceName}" off service "${serviceName}" stop || true fi statusService "${serviceName}" } function enableService() { local -r serviceName="${1}" checkNonEmptyString "${serviceName}" 'undefined service name' if [[ "$(existCommand 'systemctl')" = 'true' ]] then header "ENABLE SYSTEMD ${serviceName}" systemctl daemon-reload systemctl enable "${serviceName}" || true else header "ENABLE SERVICE ${serviceName}" chkconfig "${serviceName}" on fi statusService "${serviceName}" } function restartService() { local -r serviceName="${1}" checkNonEmptyString "${serviceName}" 'undefined service name' stopService "${serviceName}" startService "${serviceName}" } function startService() { local -r serviceName="${1}" checkNonEmptyString "${serviceName}" 'undefined service name' if [[ "$(existCommand 'systemctl')" = 'true' ]] then header "STARTING SYSTEMD ${serviceName}" systemctl daemon-reload systemctl enable "${serviceName}" || true systemctl start "${serviceName}" else header "STARTING SERVICE ${serviceName}" chkconfig "${serviceName}" on service "${serviceName}" start fi statusService "${serviceName}" } function statusService() { local -r serviceName="${1}" checkNonEmptyString "${serviceName}" 'undefined service name' if [[ "$(existCommand 'systemctl')" = 'true' ]] then header "STATUS SYSTEMD ${serviceName}" systemctl status "${serviceName}" --full --no-pager || true else header "STATUS SERVICE ${serviceName}" service "${serviceName}" status || true fi } function stopService() { local -r serviceName="${1}" checkNonEmptyString "${serviceName}" 'undefined service name' if [[ "$(existCommand 'systemctl')" = 'true' ]] then header "STOPPING SYSTEMD ${serviceName}" systemctl daemon-reload systemctl stop "${serviceName}" || true else header "STOPPING SERVICE ${serviceName}" service "${serviceName}" stop || true fi statusService "${serviceName}" } #################### # STRING UTILITIES # #################### function checkNonEmptyString() { local -r string="${1}" local -r errorMessage="${2}" if [[ "$(isEmptyString "${string}")" = 'true' ]] then if [[ "$(isEmptyString "${errorMessage}")" = 'true' ]] then fatal '\nFATAL : empty value detected' fi fatal "\nFATAL : ${errorMessage}" fi } function checkTrueFalseString() { local -r string="${1}" local -r errorMessage="${2}" if [[ "${string}" != 'true' && "${string}" != 'false' ]] then if [[ "$(isEmptyString "${errorMessage}")" = 'true' ]] then fatal "\nFATAL : '${string}' is not 'true' or 'false'" fi fatal "\nFATAL : ${errorMessage}" fi } function debug() { local -r message="${1}" if [[ "$(isEmptyString "${message}")" = 'false' ]] then echo -e "\033[1;34m${message}\033[0m" 2>&1 fi } function deleteSpaces() { local -r content="${1}" replaceString "${content}" ' ' '' } function displayVersion() { local -r message="${1}" local -r applicationName="${2}" if [[ "$(isEmptyString "${applicationName}")" = 'true' ]] then header 'DISPLAYING VERSION' else header "DISPLAYING ${applicationName} VERSION" fi info "${message}" } function encodeURL() { local -r url="${1}" local i=0 for ((i = 0; i < ${#url}; i++)) do local walker='' walker="${url:i:1}" case "${walker}" in [a-zA-Z0-9.~_-]) printf '%s' "${walker}" ;; ' ') printf + ;; *) printf '%%%X' "'${walker}" ;; esac done } function error() { local -r message="${1}" if [[ "$(isEmptyString "${message}")" = 'false' ]] then echo -e "\033[1;31m${message}\033[0m" 1>&2 fi } function escapeGrepSearchPattern() { local -r searchPattern="${1}" sed 's/[]\.|$(){}?+*^]/\\&/g' <<< "${searchPattern}" } function escapeSearchPattern() { local -r searchPattern="${1}" sed -e "s@\@@\\\\\\@@g" -e "s@\[@\\\\[@g" -e "s@\*@\\\\*@g" -e "s@\%@\\\\%@g" <<< "${searchPattern}" } function fatal() { local -r message="${1}" error "${message}" exit 1 } function formatPath() { local path="${1}" while [[ "$(grep -F '//' <<< "${path}")" != '' ]] do path="$(sed -e 's/\/\/*/\//g' <<< "${path}")" done sed -e 's/\/$//g' <<< "${path}" } function header() { local -r title="${1}" if [[ "$(isEmptyString "${title}")" = 'false' ]] then echo -e "\n\033[1;33m>>>>>>>>>> \033[1;4;35m${title}\033[0m \033[1;33m<<<<<<<<<<\033[0m\n" fi } function indentString() { local -r indentString="$(escapeSearchPattern "${1}")" local -r string="$(escapeSearchPattern "${2}")" sed "s@^@${indentString}@g" <<< "${string}" } function info() { local -r message="${1}" if [[ "$(isEmptyString "${message}")" = 'false' ]] then echo -e "\033[1;36m${message}\033[0m" 2>&1 fi } function invertTrueFalseString() { local -r string="${1}" checkTrueFalseString "${string}" if [[ "${string}" = 'true' ]] then echo 'false' && return 1 fi echo 'true' && return 0 } function isEmptyString() { local -r string="${1}" if [[ "$(trimString "${string}")" = '' ]] then echo 'true' && return 0 fi echo 'false' && return 1 } function postUpMessage() { echo -e "\n\033[1;32m¯\_(ツ)_/¯\033[0m" } function printTable() { local -r delimiter="${1}" local -r tableData="$(removeEmptyLines "${2}")" local -r colorHeader="${3}" local -r displayTotalCount="${4}" if [[ "${delimiter}" != '' && "$(isEmptyString "${tableData}")" = 'false' ]] then local -r numberOfLines="$(trimString "$(wc -l <<< "${tableData}")")" if [[ "${numberOfLines}" -gt '0' ]] then local table='' local i=1 for ((i = 1; i <= "${numberOfLines}"; i = i + 1)) do local line='' line="$(sed "${i}q;d" <<< "${tableData}")" local numberOfColumns=0 numberOfColumns="$(awk -F "${delimiter}" '{print NF}' <<< "${line}")" # Add Line Delimiter if [[ "${i}" -eq '1' ]] then table="${table}$(printf '%s#+' "$(repeatString '#+' "${numberOfColumns}")")" fi # Add Header Or Body table="${table}\n" local j=1 for ((j = 1; j <= "${numberOfColumns}"; j = j + 1)) do table="${table}$(printf '#| %s' "$(cut -d "${delimiter}" -f "${j}" <<< "${line}")")" done table="${table}#|\n" # Add Line Delimiter if [[ "${i}" -eq '1' ]] || [[ "${numberOfLines}" -gt '1' && "${i}" -eq "${numberOfLines}" ]] then table="${table}$(printf '%s#+' "$(repeatString '#+' "${numberOfColumns}")")" fi done if [[ "$(isEmptyString "${table}")" = 'false' ]] then local output='' output="$(echo -e "${table}" | column -s '#' -t | awk '/^\+/{gsub(" ", "-", $0)}1')" if [[ "${colorHeader}" = 'true' ]] then echo -e "\033[1;32m$(head -n 3 <<< "${output}")\033[0m" tail -n +4 <<< "${output}" else echo "${output}" fi fi fi if [[ "${displayTotalCount}" = 'true' && "${numberOfLines}" -ge '0' ]] then echo -e "\n\033[1;36mTOTAL ROWS : $((numberOfLines - 1))\033[0m" fi fi } function removeEmptyLines() { local -r content="${1}" echo -e "${content}" | sed '/^\s*$/d' } function repeatString() { local -r string="${1}" local -r numberToRepeat="${2}" if [[ "${string}" != '' && "$(isPositiveInteger "${numberToRepeat}")" = 'true' ]] then local -r result="$(printf "%${numberToRepeat}s")" echo -e "${result// /${string}}" fi } function replaceString() { local -r content="${1}" local -r oldValue="$(escapeSearchPattern "${2}")" local -r newValue="$(escapeSearchPattern "${3}")" sed "s@${oldValue}@${newValue}@g" <<< "${content}" } function stringToNumber() { local -r string="${1}" checkNonEmptyString "${string}" 'undefined string' if [[ "$(existCommand 'md5')" = 'true' ]] then md5 <<< "${string}" | tr -cd '0-9' elif [[ "$(existCommand 'md5sum')" = 'true' ]] then md5sum <<< "${string}" | tr -cd '0-9' else fatal '\nFATAL : md5 or md5sum command not found' fi } function stringToSearchPattern() { local -r string="$(trimString "${1}")" if [[ "$(isEmptyString "${string}")" = 'true' ]] then echo "${string}" else echo "^\s*$(sed -e 's/\s\+/\\s+/g' <<< "$(escapeSearchPattern "${string}")")\s*$" fi } function trimString() { local -r string="${1}" sed 's,^[[:blank:]]*,,' <<< "${string}" | sed 's,[[:blank:]]*$,,' } function warn() { local -r message="${1}" if [[ "$(isEmptyString "${message}")" = 'false' ]] then echo -e "\033[1;33m${message}\033[0m" 1>&2 fi } #################### # SYSTEM UTILITIES # #################### function addSwapSpace() { local swapSize="${1}" local swapFile="${2}" header 'ADDING SWAP SPACE' # Set Default Values if [[ "$(isEmptyString "${swapSize}")" = 'true' ]] then swapSize='1024000' fi if [[ "$(isEmptyString "${swapFile}")" = 'true' ]] then swapFile='/mnt/swapfile' fi if [[ -f "${swapFile}" ]] then swapoff "${swapFile}" fi rm -f "${swapFile}" touch "${swapFile}" # Create Swap File dd if=/dev/zero of="${swapFile}" bs=1024 count="${swapSize}" mkswap "${swapFile}" chmod 600 "${swapFile}" swapon "${swapFile}" # Config Swap File System local -r fstabConfig="${swapFile} swap swap defaults 0 0" appendToFileIfNotFound '/etc/fstab' "$(stringToSearchPattern "${fstabConfig}")" "${fstabConfig}" 'true' 'false' 'true' # Display Swap Status free -m } function checkExistCommand() { local -r command="${1}" local -r errorMessage="${2}" if [[ "$(existCommand "${command}")" = 'false' ]] then if [[ "$(isEmptyString "${errorMessage}")" = 'true' ]] then fatal "\nFATAL : command '${command}' not found" fi fatal "\nFATAL : ${errorMessage}" fi } function checkRequirePorts() { local -r ports=("${@}") installPackages 'lsof' local -r headerRegex='^COMMAND\s\+PID\s\+USER\s\+FD\s\+TYPE\s\+DEVICE\s\+SIZE\/OFF\s\+NODE\s\+NAME$' local -r status="$(lsof -i -n -P | grep "\( (LISTEN)$\)\|\(${headerRegex}\)")" local open='' local port='' for port in "${ports[@]}" do local found='' found="$(grep -i ":${port} (LISTEN)$" <<< "${status}" || echo)" if [[ "$(isEmptyString "${found}")" = 'false' ]] then open="${open}\n${found}" fi done if [[ "$(isEmptyString "${open}")" = 'false' ]] then echo -e "\033[1;31mFollowing ports are still opened. Make sure you uninstall or stop them before a new installation!\033[0m" echo -e -n "\033[1;34m\n$(grep "${headerRegex}" <<< "${status}")\033[0m" echo -e "\033[1;36m${open}\033[0m\n" exit 1 fi } function displayOpenPorts() { local -r sleepTimeInSecond="${1}" installPackages 'lsof' header 'DISPLAYING OPEN PORTS' if [[ "$(isEmptyString "${sleepTimeInSecond}")" = 'false' ]] then sleep "${sleepTimeInSecond}" fi lsof -i -n -P | grep -i ' (LISTEN)$' | sort -f } function existCommand() { local -r command="${1}" if [[ "$(which "${command}" 2> '/dev/null')" = '' ]] then echo 'false' && return 1 fi echo 'true' && return 0 } function existDisk() { local -r disk="${1}" local -r foundDisk="$(fdisk -l "${disk}" 2> '/dev/null' | grep -E -i -o "^Disk\s+$(escapeGrepSearchPattern "${disk}"): ")" if [[ "$(isEmptyString "${disk}")" = 'false' && "$(isEmptyString "${foundDisk}")" = 'false' ]] then echo 'true' && return 0 fi echo 'false' && return 1 } function existDiskMount() { local -r disk="$(escapeGrepSearchPattern "${1}")" local -r mountOn="$(escapeGrepSearchPattern "${2}")" local -r foundMount="$(df | grep -E "^${disk}\s+.*\s+${mountOn}$")" if [[ "$(isEmptyString "${foundMount}")" = 'true' ]] then echo 'false' && return 1 fi echo 'true' && return 0 } function existModule() { local -r module="${1}" checkNonEmptyString "${module}" 'undefined module' if [[ "$(lsmod | awk '{ print $1 }' | grep -F -o "${module}")" = '' ]] then echo 'false' && return 1 fi echo 'true' && return 0 } function existMount() { local -r mountOn="$(escapeGrepSearchPattern "${1}")" local -r foundMount="$(df | grep -E ".*\s+${mountOn}$")" if [[ "$(isEmptyString "${foundMount}")" = 'true' ]] then echo 'false' && return 1 fi echo 'true' && return 0 } function flushFirewall() { header 'FLUSHING FIREWALL' iptables -P INPUT ACCEPT iptables -P FORWARD ACCEPT iptables -P OUTPUT ACCEPT iptables -t nat -F iptables -t mangle -F iptables -F iptables -X iptables --list saveFirewall } function isPortOpen() { local -r port="$(escapeGrepSearchPattern "${1}")" checkNonEmptyString "${port}" 'undefined port' if [[ "$(isAmazonLinuxDistributor)" = 'true' || "$(isRedHatDistributor)" = 'true' || "$(isUbuntuDistributor)" = 'true' ]] then local -r process="$(netstat -l -n -t -u | grep -E ":${port}\s+" | head -1)" elif [[ "$(isCentOSDistributor)" = 'true' || "$(isMacOperatingSystem)" = 'true' ]] then if [[ "$(isCentOSDistributor)" = 'true' ]] then installPackages 'lsof' fi local -r process="$(lsof -i -n -P | grep -E -i ":${port}\s+\(LISTEN\)$" | head -1)" else fatal '\nFATAL : only support Amazon-Linux, CentOS, Mac, RedHat, or Ubuntu OS' fi if [[ "$(isEmptyString "${process}")" = 'true' ]] then echo 'false' && return 1 fi echo 'true' && return 0 } function redirectJDKTMPDir() { local -r option="_JAVA_OPTIONS='-Djava.io.tmpdir=/var/tmp'" appendToFileIfNotFound '/etc/environment' "${option}" "${option}" 'false' 'false' 'true' appendToFileIfNotFound '/etc/profile' "${option}" "${option}" 'false' 'false' 'true' } function remountTMP() { header 'RE-MOUNTING TMP' if [[ "$(existMount '/tmp')" = 'true' ]] then mount -o 'remount,rw,exec,nosuid' -v '/tmp' else warn 'WARN : mount /tmp not found' fi } function saveFirewall() { header 'SAVING FIREWALL' local ruleFile='' for ruleFile in '/etc/iptables/rules.v4' '/etc/iptables/rules.v6' '/etc/sysconfig/iptables' '/etc/sysconfig/ip6tables' do if [[ -f "${ruleFile}" ]] then if [[ "$(grep -F '6' <<< "${ruleFile}")" = '' ]] then iptables-save > "${ruleFile}" else ip6tables-save > "${ruleFile}" fi info "${ruleFile}" cat "${ruleFile}" echo fi done } ############################ # USER AND GROUP UTILITIES # ############################ function addUser() { local -r userLogin="${1}" local -r groupName="${2}" local -r createHome="${3}" local -r systemAccount="${4}" local -r allowLogin="${5}" checkNonEmptyString "${userLogin}" 'undefined user login' checkNonEmptyString "${groupName}" 'undefined group name' # Options if [[ "${createHome}" = 'true' ]] then local -r createHomeOption=('-m') else local -r createHomeOption=('-M') fi if [[ "${allowLogin}" = 'true' ]] then local -r allowLoginOption=('-s' '/bin/bash') else local -r allowLoginOption=('-s' '/bin/false') fi # Add Group groupadd -f -r "${groupName}" # Add User if [[ "$(existUserLogin "${userLogin}")" = 'true' ]] then if [[ "$(isUserLoginInGroupName "${userLogin}" "${groupName}")" = 'false' ]] then usermod -a -G "${groupName}" "${userLogin}" fi # Not Exist Home if [[ "${createHome}" = 'true' ]] then local -r userHome="$(getUserHomeFolder "${userLogin}")" if [[ "$(isEmptyString "${userHome}")" = 'true' || ! -d "${userHome}" ]] then mkdir -m 700 -p "/home/${userLogin}" chown -R "${userLogin}:${groupName}" "/home/${userLogin}" fi fi else if [[ "${systemAccount}" = 'true' ]] then useradd "${createHomeOption[@]}" -r "${allowLoginOption[@]}" -g "${groupName}" "${userLogin}" else useradd "${createHomeOption[@]}" "${allowLoginOption[@]}" -g "${groupName}" "${userLogin}" fi fi } function addUserAuthorizedKey() { local -r userLogin="${1}" local -r groupName="${2}" local -r sshRSA="${3}" configUserSSH "${userLogin}" "${groupName}" "${sshRSA}" 'authorized_keys' } function addUserSSHKnownHost() { local -r userLogin="${1}" local -r groupName="${2}" local -r sshRSA="${3}" configUserSSH "${userLogin}" "${groupName}" "${sshRSA}" 'known_hosts' } function addUserToSudoWithoutPassword() { local -r userLogin="${1}" echo "${userLogin} ALL=(ALL) NOPASSWD:ALL" > "/etc/sudoers.d/${userLogin}" chmod 440 "/etc/sudoers.d/${userLogin}" } function checkExistGroupName() { local -r groupName="${1}" if [[ "$(existGroupName "${groupName}")" = 'false' ]] then fatal "\nFATAL : group name '${groupName}' not found" fi } function checkExistUserLogin() { local -r userLogin="${1}" if [[ "$(existUserLogin "${userLogin}")" = 'false' ]] then fatal "\nFATAL : user login '${userLogin}' not found" fi } function checkRequireNonRootUser() { if [[ "$(whoami)" = 'root' ]] then fatal '\nFATAL : non root login required' fi } function checkRequireRootUser() { checkRequireUserLogin 'root' } function checkRequireUserLogin() { local -r userLogin="${1}" if [[ "$(whoami)" != "${userLogin}" ]] then fatal "\nFATAL : user login '${userLogin}' required" fi } function configUserGIT() { local -r userLogin="${1}" local -r gitUserName="${2}" local -r gitUserEmail="${3}" header "CONFIGURING GIT FOR USER ${userLogin}" checkExistUserLogin "${userLogin}" checkNonEmptyString "${gitUserName}" 'undefined git user name' checkNonEmptyString "${gitUserEmail}" 'undefined git user email' su -l "${userLogin}" -c "git config --global user.name '${gitUserName}'" su -l "${userLogin}" -c "git config --global user.email '${gitUserEmail}'" su -l "${userLogin}" -c 'git config --global push.default simple' info "$(su -l "${userLogin}" -c 'git config --list')" } function configUserSSH() { local -r userLogin="${1}" local -r groupName="${2}" local -r sshRSA="${3}" local -r configFileName="${4}" header "CONFIGURING ${configFileName} FOR USER ${userLogin}" checkExistUserLogin "${userLogin}" checkExistGroupName "${groupName}" checkNonEmptyString "${sshRSA}" 'undefined SSH-RSA' checkNonEmptyString "${configFileName}" 'undefined config file' local -r userHome="$(getUserHomeFolder "${userLogin}")" checkExistFolder "${userHome}" mkdir -m 700 -p "${userHome}/.ssh" touch "${userHome}/.ssh/${configFileName}" appendToFileIfNotFound "${userHome}/.ssh/${configFileName}" "${sshRSA}" "${sshRSA}" 'false' 'false' 'false' chmod 600 "${userHome}/.ssh/${configFileName}" chown -R "${userLogin}:${groupName}" "${userHome}/.ssh" cat "${userHome}/.ssh/${configFileName}" } function deleteUser() { local -r userLogin="${1}" if [[ "$(existUserLogin "${userLogin}")" = 'true' ]] then userdel -f -r "${userLogin}" 2> '/dev/null' || true fi } function existGroupName() { local -r group="${1}" if [[ "$(grep -E -o "^${group}:" '/etc/group')" = '' ]] then echo 'false' && return 1 fi echo 'true' && return 0 } function existUserLogin() { local -r user="${1}" if ( id -u "${user}" > '/dev/null' 2>&1 ) then echo 'true' && return 0 fi echo 'false' && return 1 } function generateSSHPublicKeyFromPrivateKey() { local -r userLogin="${1}" local groupName="${2}" # Set Default if [[ "$(isEmptyString "${groupName}")" = 'true' ]] then groupName="${userLogin}" fi # Validate Input checkExistUserLogin "${userLogin}" checkExistGroupName "${groupName}" local -r userHome="$(getUserHomeFolder "${userLogin}")" checkExistFile "${userHome}/.ssh/id_rsa" # Generate SSH Public Key header "GENERATING SSH PUBLIC KEY FOR USER '${userLogin}' FROM PRIVATE KEY" rm -f "${userHome}/.ssh/id_rsa.pub" su -l "${userLogin}" -c "ssh-keygen -f '${userHome}/.ssh/id_rsa' -y > '${userHome}/.ssh/id_rsa.pub'" chmod 600 "${userHome}/.ssh/id_rsa.pub" chown "${userLogin}:${groupName}" "${userHome}/.ssh/id_rsa.pub" cat "${userHome}/.ssh/id_rsa.pub" } function generateUserSSHKey() { local -r userLogin="${1}" local groupName="${2}" # Set Default if [[ "$(isEmptyString "${groupName}")" = 'true' ]] then groupName="${userLogin}" fi # Validate Input checkExistUserLogin "${userLogin}" checkExistGroupName "${groupName}" local -r userHome="$(getUserHomeFolder "${userLogin}")" checkExistFolder "${userHome}" # Generate SSH Key header "GENERATING SSH KEY FOR USER '${userLogin}'" rm -f "${userHome}/.ssh/id_rsa" "${userHome}/.ssh/id_rsa.pub" mkdir -m 700 -p "${userHome}/.ssh" chown "${userLogin}:${groupName}" "${userHome}/.ssh" su -l "${userLogin}" -c "ssh-keygen -q -t rsa -N '' -f '${userHome}/.ssh/id_rsa'" chmod 600 "${userHome}/.ssh/id_rsa" "${userHome}/.ssh/id_rsa.pub" chown "${userLogin}:${groupName}" "${userHome}/.ssh/id_rsa" "${userHome}/.ssh/id_rsa.pub" cat "${userHome}/.ssh/id_rsa.pub" } function getCurrentUserHomeFolder() { getUserHomeFolder "$(whoami)" } function getProfileFilePath() { local -r user="${1}" local -r userHome="$(getUserHomeFolder "${user}")" if [[ "$(isEmptyString "${userHome}")" = 'false' && -d "${userHome}" ]] then local -r bashProfileFilePath="${userHome}/.bash_profile" local -r profileFilePath="${userHome}/.profile" if [[ ! -f "${bashProfileFilePath}" && -f "${profileFilePath}" ]] then echo "${profileFilePath}" else echo "${bashProfileFilePath}" fi fi } function getUserGroupName() { local -r userLogin="${1}" checkExistUserLogin "${userLogin}" id -g -n "${userLogin}" } function getUserHomeFolder() { local -r user="${1}" if [[ "$(isEmptyString "${user}")" = 'false' ]] then local -r homeFolder="$(eval "echo ~${user}")" if [[ "${homeFolder}" = "\~${user}" ]] then echo else echo "${homeFolder}" fi else echo fi } function isUserLoginInGroupName() { local -r userLogin="${1}" local -r groupName="${2}" checkNonEmptyString "${userLogin}" 'undefined user login' checkNonEmptyString "${groupName}" 'undefined group name' if [[ "$(existUserLogin "${userLogin}")" = 'true' ]] && [[ "$(groups "${userLogin}" | grep "\b${groupName}\b")" != '' ]] then echo 'true' && return 0 fi echo 'false' && return 1 }