diff --git a/aws-functions.sh b/aws-functions.sh index 11d4261..62c4bb2 100644 --- a/aws-functions.sh +++ b/aws-functions.sh @@ -57,4 +57,138 @@ function createRole() { ROLE_NAME="$1" POLICY_DOCUMENT="$2" aws iam create-role --role-name "${ROLE_NAME}" --no-paginate --assume-role-policy-document "file://${POLICY_DOCUMENT}" +} + +function getAssumeRole() { + ROLE_ARN=$1 + + role_output=$(aws sts assume-role --role-arn "$ROLE_ARN" --role-session-name default) + + if [ $? -ne 0 ]; then + echo "Failed to assume role :- $ROLE_ARN." + exit 1 + fi + + AWS_ACCESS_KEY_ID=$(echo $role_output | jq -r '.Credentials.AccessKeyId') + AWS_SECRET_ACCESS_KEY=$(echo $role_output | jq -r '.Credentials.SecretAccessKey') + AWS_SESSION_TOKEN=$(echo $role_output | jq -r '.Credentials.SessionToken') + + export AWS_ACCESS_KEY_ID + export AWS_SECRET_ACCESS_KEY + export AWS_SESSION_TOKEN +} + +function set_aws_credentials() { + CREDENTIAL_MANAGEMENT_NAME=$1 + + aws_creds=$(getEncryptedCredential "$CREDENTIAL_MANAGEMENT" "$CREDENTIAL_MANAGEMENT_NAME.CREDENTIAL_KEY_VALUE_PAIR") + + aws_access_key=$(echo $aws_creds | sed "s/'/\"/g" | jq -r '.aws_access_key') + aws_secret_access_key=$(echo $aws_creds | sed "s/'/\"/g" | jq -r '.aws_secret_access_key') + + export AWS_ACCESS_KEY_ID="$aws_access_key" + export AWS_SECRET_ACCESS_KEY="$aws_secret_access_key" + } + +function check_aws_authentication() { + if ! aws sts get-caller-identity &>/dev/null; then + logErrorMessage "Failed to authenticate with AWS CLI. Please configure AWS CLI authentication." + exit 1 + else + logInfoMessage "Successfully authenticated with AWS CLI." + fi +} + +function create_ec2_instance() { + AMI_ID="$1" + INSTANCE_TYPE="$2" + SSH_KEY_NAME="$3" + SUBNET_ID="$4" + SECURITY_GROUP_IDS="$5" + INSTANCE_COUNT="$6" + INSTANCE_NAME="$7" + BUILDX_ENABLE="$8" + TAG_SPECIFICATIONS="${9}" + USER_DATA="${10:-}" + + EC2_CREATE_CMD="aws ec2 run-instances \ + --image-id \"$AMI_ID\" \ + --instance-type \"$INSTANCE_TYPE\" \ + --key-name \"$SSH_KEY_NAME\" \ + --subnet-id \"$SUBNET_ID\" \ + --security-group-ids \"$SECURITY_GROUP_IDS\" \ + --count \"$INSTANCE_COUNT\" \ + --tag-specifications \"$TAG_SPECIFICATIONS\"" + + # Append user-data if provided + if [ -n "$USER_DATA" ]; then + EC2_CREATE_CMD="$EC2_CREATE_CMD --user-data \"$USER_DATA\"" + fi + + EC2_CREATE_OUTPUT=$(eval "$EC2_CREATE_CMD") + + if [ $? -ne 0 ]; then + echo "Error creating EC2 instance." + echo "$EC2_CREATE_OUTPUT" + return 1 + fi + + echo "$EC2_CREATE_OUTPUT" + return 0 +} + +check_instance_status() { + local INSTANCE_ID="$1" + local INSTANCE_TYPE="$2" + + logInfoMessage "Checking $INSTANCE_TYPE instance [ID: $INSTANCE_ID]." + + INSTANCE_STATE=$(aws ec2 describe-instances --instance-ids "$INSTANCE_ID" --query "Reservations[].Instances[].State.Name" --output text) + + if [[ "$INSTANCE_STATE" == "terminated" || "$INSTANCE_STATE" == "stopped" ]]; then + logInfoMessage "$INSTANCE_TYPE instance [ID: $INSTANCE_ID] is in $INSTANCE_STATE state. Skipping status check and moving on." + return 1 + fi + + logInfoMessage "Waiting for $INSTANCE_TYPE instance [ID: $INSTANCE_ID] to be in 'running' state and pass status checks." + + MAX_WAIT_TIME=600 # Maximum wait time in seconds (10 minutes) + SLEEP_INTERVAL=15 # Interval to check the status (15 seconds) + TOTAL_WAIT=0 + + while true; do + INSTANCE_STATE=$(aws ec2 describe-instances --instance-ids "$INSTANCE_ID" --query "Reservations[].Instances[].State.Name" --output text) + INSTANCE_STATUS_CHECK=$(aws ec2 describe-instance-status --instance-ids "$INSTANCE_ID" --query "InstanceStatuses[].InstanceStatus.Status" --output text) + + logInfoMessage "$INSTANCE_TYPE instance [ID: $INSTANCE_ID] current state: $INSTANCE_STATE" + logInfoMessage "$INSTANCE_TYPE instance [ID: $INSTANCE_ID] status check: $INSTANCE_STATUS_CHECK" + + if [ "$INSTANCE_STATE" = "running" ] && [ "$INSTANCE_STATUS_CHECK" = "ok" ]; then + logInfoMessage "$INSTANCE_TYPE instance [ID: $INSTANCE_ID] is now running and passed all status checks." + return 0 + fi + + if [ "$TOTAL_WAIT" -ge "$MAX_WAIT_TIME" ]; then + logErrorMessage "Timeout reached for $INSTANCE_TYPE instance [ID: $INSTANCE_ID]. Not in 'running' state or did not pass status checks." + return 1 + fi + + sleep $SLEEP_INTERVAL + TOTAL_WAIT=$((TOTAL_WAIT + SLEEP_INTERVAL)) + done +} + +terminate_instance() { + local INSTANCE_ID="$1" + local INSTANCE_TYPE="$2" + + INSTANCE_STATE=$(aws ec2 describe-instances --instance-ids "$INSTANCE_ID" --query "Reservations[].Instances[].State.Name" --output text) + + if [[ "$INSTANCE_STATE" != "terminated" && "$INSTANCE_STATE" != "stopped" ]]; then + logErrorMessage "Terminating $INSTANCE_TYPE instance [ID: $INSTANCE_ID]." + aws ec2 terminate-instances --instance-ids "$INSTANCE_ID" + logInfoMessage "$INSTANCE_TYPE instance [ID: $INSTANCE_ID] has been terminated." + else + logInfoMessage "$INSTANCE_TYPE instance [ID: $INSTANCE_ID] is already in $INSTANCE_STATE state. No need to terminate." + fi } \ No newline at end of file diff --git a/docker-functions.sh b/docker-functions.sh new file mode 100755 index 0000000..2a55460 --- /dev/null +++ b/docker-functions.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# Function to extract the base image from a filtered Dockerfile string +# This string contains entries of all the lines starting with FROM +getBaseImageFromFilteredDockerfile() { + local allFromEntries="$1" + local base_img + + while IFS= read -r line; do + base_img=$(echo "$line" | grep '^FROM ' | awk '{print $2}') + done <<< "$allFromEntries" + + echo "${base_img}" +} diff --git a/file-functions.sh b/file-functions.sh index d3b25ae..b100d4b 100644 --- a/file-functions.sh +++ b/file-functions.sh @@ -20,12 +20,18 @@ function fileContainsString() { function getLineForAString() { FILEPATH="$1" TEXT="$2" - grep "${TEXT}" "${FILEPATH}" + grep "${TEXT}" "${FILEPATH}" } function textExistsInALine(){ LINE="$1" TEXT="$2" - echo "${LINE}" | grep -q "${TEXT}" - echo "$?" + # Split single comma separated string into array + IFS="," read -r -a TEXT_ARRAY <<< "$TEXT" + for ITEM in "${TEXT_ARRAY[@]}"; do + if [ "$ITEM" == "$LINE" ]; then + return 0 + fi + done + return 1 } \ No newline at end of file diff --git a/functions.sh b/functions.sh index fee382f..d6b508f 100755 --- a/functions.sh +++ b/functions.sh @@ -32,14 +32,65 @@ function getRepositoryTag() { echo "$BUILD_REPOSITORY_TAG" } -function getDockerfileParentPath() { +function getDockerfilePath() { DOCKERFILE_ENTRY=$(jq -r .build_detail.dockerfile_path < /bp/data/environment_build) - getNthTextInALine "$DOCKERFILE_ENTRY" : 2 + echo "$DOCKERFILE_ENTRY" } -function getDockerfileName() { - DOCKERFILE_ENTRY=$(jq -r .build_detail.dockerfile_path < /bp/data/environment_build) - getNthTextInALine "$DOCKERFILE_ENTRY" : 1 +function getGitRepo() { + GIT_REPO_URL=$(jq -r .git_repo.git_url < /bp/data/environment_build) + echo "$GIT_REPO_URL" +} + +function getGitBranch() { + GIT_BRANCH_NAME=$(jq -r .git_repo.branch_name < /bp/data/environment_build) + echo "$GIT_BRANCH_NAME" +} + +function getGitUrl() { + GIT_BRANCH_NAME=$(jq -r .git_repo.git_url < /bp/data/environment_build) + echo "$GIT_BRANCH_NAME" +} + +function getDeploymentTimestamp() { + Deployment_Timestamp=$(jq -r .build_info.deployment_trigger_time < /bp/data/deploy_stateless_app) + echo "$Deployment_Timestamp" +} + +function getDeploymentUser() { + Deployment_User=$(jq -r .build_info.user < /bp/data/deploy_stateless_app) + echo "$Deployment_User" +} + +function getDeploymentImage() { + Deployment_Image=$(jq -r '.addition_meta_data.environment_variables.envs_list[] | select(.env_key == "image.url") | .env_value' < /bp/data/deploy_stateless_app) + echo "$Deployment_Image" +} + +function getGitCommitSha() { + Git_Commit_Sha=$(jq -r .build_info.commit_sha < /bp/data/deploy_stateless_app) + echo "$Git_Commit_Sha" +} + +function getGitCommitMsg() { + Git_Commit_Msg=$(jq -r .build_info.commit_msg < /bp/data/deploy_stateless_app) + echo "$Git_Commit_Msg" +} + +function getDeploymentGitBranch() { + Deployment_Git_branch=$(jq -r .build_info.git_branch < /bp/data/deploy_stateless_app) + echo "$Deployment_Git_branch" +} + +function getNewrelicApm() { + Newrelic_apm=$(jq -r '.addition_meta_data.environment_variables.envs_list[] | select(.env_key == "APM_NAME") | .env_value' < /bp/data/deploy_stateless_app) + echo "$Newrelic_apm" +} + + +function getDeploymentGitUrl() { + Deployment_Git_Url=$(jq -r .build_info.git_url < /bp/data/deploy_stateless_app) + echo "$Deployment_Git_Url" } function saveTaskStatus() { @@ -61,4 +112,192 @@ function saveTaskStatus() { fi } +function getDecryptedCredential() { + local fernet_key="$1" + local encrypted_value="$2" + + python3 -c " +from cryptography.fernet import Fernet + +fernet_key = '$fernet_key' +f = Fernet(fernet_key.encode('utf-8')) +encrypted_value = b'$encrypted_value' + +try: + decrypted_value = f.decrypt(encrypted_value) + print(decrypted_value.decode()) +except Exception as e: + print(f'Decryption error: {e}') +" +} + +function passwordStrengthChecker() { + local password="$1" + + if [ -z "$password" ]; then + logErrorMessage "password cannot be empty." + exit 1 + fi + + if [ "${#password}" -ge 8 ] && [[ $password == *[A-Za-z]* ]] && [[ $password == *[0-9]* ]] && [[ $password == *['#?!@$\ %^\&*-']* ]] + then + true + else + logErrorMessage "Weak password. Please ensure the password meets the criteria: at least 8 characters, one uppercase letter, one lowercase letter, one digit, and one special character." + exit 1 + fi +} + +function validDBname() { + local db_name="$1" + + if [ -z "$db_name" ]; then + logErrorMessage "Database name cannot be empty." + exit 1 + fi + + if [[ "$db_name" =~ ^[a-zA-Z0-9_]+$ ]]; then + true + else + logErrorMessage "Invalid characters in the database name [$db_name]. Only alphanumeric characters (a-zA-Z), digits (1), underscore (_) are allowed." + exit 1 + fi +} + +function validDBusername() { + local username="$1" + + if [ -z "$username" ]; then + logErrorMessage "Username name cannot be empty." + exit 1 + fi + + if [[ "$username" =~ ^[a-zA-Z0-9_]+$ ]]; then + true + else + logErrorMessage "Invalid characters in the username [$username]. Only alphanumeric characters (a-zA-Z), digits (1), underscore (_) are allowed." + exit 1 + fi +} +function getEncryptedCredential() { + local credentialManagement="$1" + local credentialKey="$2" + + encrypted_value=$(echo "$credentialManagement" | jq -r ".$credentialKey") + echo "$encrypted_value" +} + +function mysqlcheckDatabaseConnection() { + local username="$1" + local password="$2" + local host="$3" + export MYSQL_PWD="$password" + mysql -u "$username" -h "$host" -e "SELECT 1;" || { + logErrorMessage "Failed to login to the database server. Check your credentials and connection." + exit 1 + } +} + + +function mysqlcreateDatabase() { + local username="$1" + local password="$2" + local host="$3" + local dbName="$4" + export MYSQL_PWD="$password" + + mysql -u "$username" -h "$host" -e "CREATE DATABASE $dbName;" || { + logErrorMessage "Failed to create the database." + exit 1 + } +} + +function mysqlcreateUser() { + local username="$1" + local password="$2" + local host="$3" + local dbName="$4" + local userName="$5" + local userPassword="$6" + export MYSQL_PWD="$password" + + mysql -u "$username" -h "$host" -e "CREATE USER '$userName'@'$host' IDENTIFIED BY '$userPassword';" || { + logErrorMessage "Failed to create the user [$userName]." + exit 1 + } +} + +function mysqlgrantPrivileges() { + local username="$1" + local password="$2" + local host="$3" + local dbName="$4" + local userName="$5" + export MYSQL_PWD="$password" + + mysql -u "$username" -h "$host" -e "GRANT ALL PRIVILEGES ON $dbName.* TO '$userName'@'$host'; FLUSH PRIVILEGES;" || { + logErrorMessage "Failed to give privileges to the user [$userName]." + exit 1 + } +} + +function mysqlcheckUserPrivileges() { + local username="$1" + local password="$2" + local host="$3" + local userName="$4" + export MYSQL_PWD="$password" + + mysql -u "$username" -h "$host" -e "SHOW GRANTS FOR '$userName'@'$host';" || { + logErrorMessage "Failed to check privileges for the user [$userName]." + exit 1 + } +} + +function getProjectEnv() { + PROJECT_ENV_NAME=$(jq -r .environment.project_env < /bp/data/environment_build) + getNthTextInALine "$PROJECT_ENV_NAME" : 1 +} + +function getServiceName() { + PROJECT_SVC_NAME=$(jq -r .component.name < /bp/data/environment_build) + getNthTextInALine "$PROJECT_SVC_NAME" : 1 +} + +function jsonOutputWithoutArray() { + file_name="$1" + output_vars="$2" + + file_content="" + if [[ -f "$file_name" ]]; then + file_content=$(<"$file_name") + fi + [[ "$file_content" != "["* ]] && file_content="[]" + + updated_content=$(jq -c ". += [$output_vars]" <<< "$file_content") + + echo "$updated_content" | jq "." > "$file_name" + + echo "Job step response updated in: $file_name" +} + +function jsonOutput() { + file_name="$1" + output_vars="$2" + + file_content="" + if [[ -f "$file_name" && -s "$file_name" ]]; then + file_content=$(<"$file_name") + fi + + if [[ -n "$file_content" ]]; then + updated_content=$(jq -c --argjson vars "$output_vars" '. += [$vars]' <<< "$file_content") + else + updated_content="$output_vars" + fi + + echo "$updated_content" | jq "." > "$file_name" + + echo "Job step response updated in: $file_name" +} diff --git a/git-functions.sh b/git-functions.sh index 0400e8c..02cac49 100644 --- a/git-functions.sh +++ b/git-functions.sh @@ -14,6 +14,7 @@ function findConflictingFiles() { SRC_BRANCH="$1" TGT_BRANCH="$2" + git checkout -q "${SRC_BRANCH}" git checkout -q "${TGT_BRANCH}" # git pull origin "${TGT_BRANCH}" @@ -21,7 +22,9 @@ function findConflictingFiles() { git merge -q "$SRC_BRANCH" 1> /dev/null conflicts=$(git diff --name-only --diff-filter=U) - git merge --abort + if [ -n "${conflicts}" ]; then + git merge --abort + fi git checkout -q "${TGT_BRANCH}" git branch -q -D temp_merge_branch echo "$conflicts" @@ -36,12 +39,34 @@ function getLastAuthorOfFile() { git log -1 --pretty=format:"%an" "${FILE}" } -function getLastAuthorOfFiles() { - BRANCH="$1" - FILES="$2" - for FILE in "${FILES[@]}" +function listAuthorsOfFilesAcrossBranches() { + SRC_BRANCH="$1" + TGT_BRANCH="$2" + CONFLICTING_FILES="$3" + echo File,${SRC_BRANCH},${TGT_BRANCH} > fileAuthors.tmp + # echo "Conflicting files variable: [${CONFLICTING_FILES}]" + for FILE in ${CONFLICTING_FILES} do - author=$(getLastAuthorOfFile "$BRANCH" "$FILE") - echo "${FILE}: ${author}" + # echo "Processing file [${FILE}]" + src_branch_author=`getLastAuthorOfFile "${SRC_BRANCH}" "${FILE}"` + # echo "Source branch Author: [${src_branch_author}]" + tgt_branch_author=`getLastAuthorOfFile "${TGT_BRANCH}" "${FILE}"` + # echo "Target branch Author: [${tgt_branch_author}]" + echo "$FILE,${src_branch_author},${tgt_branch_author}" >> fileAuthors.tmp done + + cat fileAuthors.tmp | csvlook +} + +branch_exists() { + local branch_name="$1" + + # Check if the branch exists by using "git show-ref" and "grep" + if git show-ref --verify --quiet "refs/heads/$branch_name"; then + echo "Branch '$branch_name' exists." + return 0 # Branch exists + else + echo "Branch '$branch_name' does not exist." + return 1 # Branch does not exist + fi }