diff --git a/infrastructure/grafana/non-prod/docker/build_push_to_ecr.sh b/infrastructure/grafana/non-prod/docker/build_push_to_ecr.sh index 7d2a33124..81775146b 100755 --- a/infrastructure/grafana/non-prod/docker/build_push_to_ecr.sh +++ b/infrastructure/grafana/non-prod/docker/build_push_to_ecr.sh @@ -1,49 +1,38 @@ #!/bin/bash +# Build the Grafana docker image. +# This will be done manually. +# We assume the ECR artifacts have been created already by the Makefile. + # Set variables dirname=$(dirname "${0}") DOCKERFILE_DIR=$(realpath "${dirname}") echo "DOCKERFILE_DIR: ${DOCKERFILE_DIR}" -# if parameter not passed, prompt for the environment. -# Do not accept response if it is not one of the following: prod, int, ref, internal-dev -# loop until valid response is received -if [[ -z "${1}" ]]; then - while true; do - read -r -p "Enter the environment (prod, int, ref, internal-dev): " ENVIRONMENT - case "${ENVIRONMENT}" in - prod|int|ref|internal-dev) - break - ;; - *) - echo "Invalid environment. Please enter one of: prod, int, ref, internal-dev." - ;; - esac - done -else - ENVIRONMENT="${1}" -fi -# Check if the environment is valid -if [[ ! "${ENVIRONMENT}" =~ ^(prod|int|ref|internal-dev)$ ]]; then - echo "Invalid environment. Please enter one of: prod, int, ref, internal-dev." - exit 1 +# Import the terraform's .env file; it should contain the ENVIRONMENT +source ../terraform/.env + +# If it doesn't, prompt for the environment. +# Do not accept response if it is not one of the following: dev, preprod, prod + +environments=(dev preprod prod) +if [[ ! "${ENVIRONMENT}" =~ "$environments" ]] ; then + echo "Invalid environment: ${ENVIRONMENT}" + read -r -p "Please enter one of: ${environments[*]}: " ENVIRONMENT + if [[ ! "${ENVIRONMENT}" =~ "$environments" ]] ; then + echo "Invalid environment" + exit 1 + fi fi # Set the prefix and other variables PREFIX="imms-${ENVIRONMENT}" -AWS_REGION="eu-west-2" ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) REPOSITORY_NAME="${PREFIX}-grafana-app" IMAGE_TAG="11.0.0-22.04_stable" LOCAL_IMAGE_NAME="${REPOSITORY_NAME}:${IMAGE_TAG}" IMAGE_NAME="${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${LOCAL_IMAGE_NAME}" -TAGS='[ - {"Key": "Environment", "Value": "non-prod"}, - {"Key": "Project", "Value": "immunisation-fhir-api-grafana"}, - {"Key": "Environment", "Value": "'"${ENVIRONMENT}"'"} -]' -LIFECYCLE_POLICY_FILE="lifecycle-policy.json" # Change to the directory containing the Dockerfile if ! cd "${DOCKERFILE_DIR}"; then @@ -57,17 +46,6 @@ if [[ ! -f Dockerfile ]]; then exit 1 fi -# Create ECR repository if it does not exist -if ! aws ecr describe-repositories --repository-names "${REPOSITORY_NAME}" --region "${AWS_REGION}" > /dev/null 2>&1; then - echo "Creating ECR repository: ${REPOSITORY_NAME}" - aws ecr create-repository --repository-name "${REPOSITORY_NAME}" --region "${AWS_REGION}" - # Add tags to the repository - aws ecr tag-resource --resource-arn "arn:aws:ecr:${AWS_REGION}:${ACCOUNT_ID}:repository/${REPOSITORY_NAME}" --tags "${TAGS}" -fi - -# Apply lifecycle policy to the ECR repository -aws ecr put-lifecycle-policy --repository-name "${REPOSITORY_NAME}" --lifecycle-policy-text "file://${LIFECYCLE_POLICY_FILE}" --region "${AWS_REGION}" - printf "Building and pushing Docker image to ECR...\n" # Authenticate Docker to ECR aws ecr get-login-password --region "${AWS_REGION}" | docker login --username AWS --password-stdin "${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com" diff --git a/infrastructure/grafana/non-prod/terraform/.terraform.lock.hcl b/infrastructure/grafana/non-prod/terraform/.terraform.lock.hcl index d46ded729..09e6eb2c1 100644 --- a/infrastructure/grafana/non-prod/terraform/.terraform.lock.hcl +++ b/infrastructure/grafana/non-prod/terraform/.terraform.lock.hcl @@ -6,6 +6,7 @@ provider "registry.terraform.io/hashicorp/aws" { constraints = "~> 6.0" hashes = [ "h1:RwoFuX1yGMVaKJaUmXDKklEaQ/yUCEdt5k2kz+/g08c=", + "h1:wzZdGs0FFmNqIgPyo9tKnGKJ37BGNSgwRrEXayL29+0=", "zh:0ba0d5eb6e0c6a933eb2befe3cdbf22b58fbc0337bf138f95bf0e8bb6e6df93e", "zh:23eacdd4e6db32cf0ff2ce189461bdbb62e46513978d33c5de4decc4670870ec", "zh:307b06a15fc00a8e6fd243abde2cbe5112e9d40371542665b91bec1018dd6e3c", @@ -27,6 +28,7 @@ provider "registry.terraform.io/hashicorp/aws" { provider "registry.terraform.io/hashicorp/null" { version = "3.2.3" hashes = [ + "h1:+AnORRgFbRO6qqcfaQyeX80W0eX3VmjadjnUFUJTiXo=", "h1:I0Um8UkrMUb81Fxq/dxbr3HLP2cecTH2WMJiwKSrwQY=", "zh:22d062e5278d872fe7aed834f5577ba0a5afe34a3bdac2b81f828d8d3e6706d2", "zh:23dead00493ad863729495dc212fd6c29b8293e707b055ce5ba21ee453ce552d", @@ -48,6 +50,17 @@ provider "registry.terraform.io/hashicorp/template" { constraints = "~> 2.2.0" hashes = [ "h1:44Le5zVomtfOfKUsH+utlMXOcHwPe4CWyCi+0f8y0XQ=", + "h1:94qn780bi1qjrbC3uQtjJh3Wkfwd5+tTtJHOb7KTg9w=", + "zh:01702196f0a0492ec07917db7aaa595843d8f171dc195f4c988d2ffca2a06386", + "zh:09aae3da826ba3d7df69efeb25d146a1de0d03e951d35019a0f80e4f58c89b53", + "zh:09ba83c0625b6fe0a954da6fbd0c355ac0b7f07f86c91a2a97849140fea49603", + "zh:0e3a6c8e16f17f19010accd0844187d524580d9fdb0731f675ffcf4afba03d16", + "zh:45f2c594b6f2f34ea663704cc72048b212fe7d16fb4cfd959365fa997228a776", + "zh:77ea3e5a0446784d77114b5e851c970a3dde1e08fa6de38210b8385d7605d451", + "zh:8a154388f3708e3df5a69122a23bdfaf760a523788a5081976b3d5616f7d30ae", + "zh:992843002f2db5a11e626b3fc23dc0c87ad3729b3b3cff08e32ffb3df97edbde", + "zh:ad906f4cebd3ec5e43d5cd6dc8f4c5c9cc3b33d2243c89c5fc18f97f7277b51d", + "zh:c979425ddb256511137ecd093e23283234da0154b7fa8b21c2687182d9aea8b2", ] } @@ -56,6 +69,7 @@ provider "registry.terraform.io/kreuzwerker/docker" { constraints = "3.6.2" hashes = [ "h1:/Oe7tViXf/xyQ4Pg8cDifMlD3RthOYkslwQiRgx7BTE=", + "h1:1K3j0xUY2D0+E+DBDQc6k1u6Al9MkuNWrIC9rnvwFSM=", "zh:22b51a8fb63481d290bdad9a221bc8c9e45d66d1a0cd45beed3f3627bf1debd8", "zh:2b902eb80a1ae033af1135cc165d192668820a7f8ea15beb5472f811c18bea1f", "zh:57815dcea28aedb86ed33924cd186aaee8bd31670bd78437a2a2daf2b00ce2ae", diff --git a/infrastructure/grafana/non-prod/terraform/Makefile b/infrastructure/grafana/non-prod/terraform/Makefile new file mode 100644 index 000000000..e383c8b86 --- /dev/null +++ b/infrastructure/grafana/non-prod/terraform/Makefile @@ -0,0 +1,63 @@ +-include .env + +environment ?= $(ENVIRONMENT) +region ?= $(AWS_REGION) + +tf_cmd = AWS_PROFILE=$(AWS_PROFILE) terraform + +bucket_name = immunisation-$(environment)-grafana-terraform-state +state_key=state/$(environment)/terraform.tfstate + +tf_state = \ + -backend-config="key=$(state_key)" \ + -backend-config="bucket=$(bucket_name)" \ + -backend-config="region=$(region)" + +tf_vars = \ + -var="environment=$(environment)" \ + -var-file="./terraform.tfvars" + +tf_bucket_vars = \ + --bucket "$(bucket_name)" \ + --region "$(region)" \ + --create-bucket-configuration LocationConstraint="$(region)" + +tf_bucket_versioning = \ + --bucket "$(bucket_name)" \ + --versioning-configuration Status=Enabled \ + +bucket-exists: + @echo 'Checking if the S3 bucket $(bucket_name) exists...' + @aws s3 ls $(bucket_name) >/dev/null 2>&1 || echo "aws s3 bucket $(bucket_name) does not exist" + +bucket-create: + aws s3api create-bucket $(tf_bucket_vars) + aws s3api put-bucket-versioning $(tf_bucket_versioning) + +init: + $(tf_cmd) init $(tf_state) -upgrade + +init-reconfigure: + $(tf_cmd) init $(tf_state) -reconfigure + +workspace: + $(tf_cmd) workspace select -or-create $(environment) && echo "Switched to workspace/environment: $(environment)" + +plan: workspace + $(tf_cmd) plan $(tf_vars) + +plan-ci: workspace + $(tf_cmd) plan $(tf_vars) -out=tfplan -input=false + +plan-changes: workspace + $(tf_cmd) plan $(tf_vars) -out=plan && $(tf_cmd) show -no-color -json plan | jq -r '.resource_changes[] | select(.change.actions[0]=="update" or .change.actions[0]=="create" or .change.actions[0]=="add") | .address' + +# TODO: the actual application will be in infrastructure/account +# this implementation of 'apply' is for test purposes +apply: workspace + $(tf_cmd) apply $(tf_vars) -auto-approve + +clean: + rm -rf build .terraform upload-key + +.PHONY : workspace init plan clean diff --git a/infrastructure/grafana/non-prod/terraform/grafana.tf b/infrastructure/grafana/non-prod/terraform/grafana.tf new file mode 100644 index 000000000..10d0c69f2 --- /dev/null +++ b/infrastructure/grafana/non-prod/terraform/grafana.tf @@ -0,0 +1,41 @@ +# S3 state bucket +resource "aws_s3_bucket" "grafana_tf_state_bucket" { + bucket = "immunisation-${var.environment}-grafana-terraform-state" + region = var.aws_region +} + +resource "aws_s3_bucket_versioning" "grafana_tf_state_bucket_versioning" { + bucket = aws_s3_bucket.grafana_tf_state_bucket.id + versioning_configuration { + status = "Enabled" + } +} + +# Grafana ECR repo +resource "aws_ecr_repository" "grafana_ecr_repository" { + name = "${local.prefix}-app" + image_scanning_configuration { + scan_on_push = true + } +} + +resource "aws_ecr_lifecycle_policy" "grafana_ecr_lifecycle_policy" { + repository = aws_ecr_repository.grafana_ecr_repository.name + + policy = jsonencode({ + rules = [ + { + rule_priority = 1 + description = "Keep only 10 images" + selection = { + count_type = "imageCountMoreThan" + count_number = 10 + tag_status = "any" + } + action = { + type = "expire" + } + } + ] + }) +} diff --git a/infrastructure/grafana/non-prod/terraform/main.tf b/infrastructure/grafana/non-prod/terraform/main.tf index 256c47013..3651d66a7 100644 --- a/infrastructure/grafana/non-prod/terraform/main.tf +++ b/infrastructure/grafana/non-prod/terraform/main.tf @@ -23,17 +23,17 @@ terraform { } provider "aws" { - region = var.aws_region - profile = "apim-dev" + region = var.aws_region + # profile = "apim-dev" default_tags { tags = var.tags } } provider "aws" { - alias = "acm_provider" - region = var.aws_region - profile = "apim-dev" + alias = "acm_provider" + region = var.aws_region + # profile = "apim-dev" } data "aws_region" "current" {} diff --git a/infrastructure/grafana/non-prod/terraform/tf_init.sh b/infrastructure/grafana/non-prod/terraform/tf_init.sh index 02488c698..e02abee1a 100755 --- a/infrastructure/grafana/non-prod/terraform/tf_init.sh +++ b/infrastructure/grafana/non-prod/terraform/tf_init.sh @@ -1,55 +1,4 @@ #!/bin/bash -# Exit immediately if a command fails -set -e - -# Check if an environment is provided -if [ -z "$1" ]; then - echo "Usage: $0 [migrate|reconfigure]" - exit 1 -fi - -ENVIRONMENT=$1 -ACTION=${2:-""} # Optional second argument for migrate or reconfigure - -# Define backend configuration -BUCKET="immunisation-grafana-terraform-state" -REGION="eu-west-2" -STATE_KEY="state/${ENVIRONMENT}/terraform.tfstate" - -# Check if the S3 bucket exists, create it if it doesn't -if ! aws s3api head-bucket --bucket "$BUCKET" 2>/dev/null; then - echo "S3 bucket $BUCKET does not exist. Creating it..." - aws s3api create-bucket \ - --bucket "$BUCKET" \ - --region "$REGION" \ - --create-bucket-configuration LocationConstraint="$REGION" - - # Enable versioning on the bucket - echo "Enabling versioning on S3 bucket $BUCKET..." - aws s3api put-bucket-versioning \ - --bucket "$BUCKET" \ - --versioning-configuration Status=Enabled -else - echo "S3 bucket $BUCKET already exists." -fi - -# Initialize Terraform with dynamic backend configuration -if [ "$ACTION" == "migrate" ]; then - terraform init -migrate-state \ - -backend-config="key=${STATE_KEY}" \ - -backend-config="bucket=${BUCKET}" \ - -backend-config="region=${REGION}" -elif [ "$ACTION" == "reconfigure" ]; then - terraform init -reconfigure \ - -backend-config="key=${STATE_KEY}" \ - -backend-config="bucket=${BUCKET}" \ - -backend-config="region=${REGION}" -else - terraform init \ - -backend-config="key=${STATE_KEY}" \ - -backend-config="bucket=${BUCKET}" \ - -backend-config="region=${REGION}" -fi - -echo "Terraform initialized for environment: ${ENVIRONMENT}" \ No newline at end of file +echo "This script file is no longer used. Use the Makefile instead." +exit 1 diff --git a/infrastructure/grafana/non-prod/terraform/variables.tf b/infrastructure/grafana/non-prod/terraform/variables.tf index 49c014b9f..539a00d8c 100644 --- a/infrastructure/grafana/non-prod/terraform/variables.tf +++ b/infrastructure/grafana/non-prod/terraform/variables.tf @@ -1,3 +1,5 @@ +variable "environment" {} + variable "project_name" { default = "immunisations" }