diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 4720edcb..25b26218 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -21,3 +21,12 @@ jobs: client-id: ${{ secrets.AZURE_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }} subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v3 + with: + terraform_wrapper: false + terraform_version: 1.11.4 + + - name: Terraform Init + run: make terraform-init diff --git a/infrastructure/environments/poc/variables.sh b/infrastructure/environments/poc/variables.sh index 7a6b4eaf..46619cfd 100644 --- a/infrastructure/environments/poc/variables.sh +++ b/infrastructure/environments/poc/variables.sh @@ -1,4 +1,6 @@ ENVIRONMENT=poc AZURE_SUBSCRIPTION="Lung Cancer Screening - Dev" +HUB_SUBSCRIPTION="Lung Cancer Screening - Dev" +STORAGE_ACCOUNT_RG=rg-tfstate-poc-uks TERRAFORM_MODULES_REF=main ENABLE_SOFT_DELETE=false diff --git a/infrastructure/terraform/providers.tf b/infrastructure/terraform/providers.tf new file mode 100644 index 00000000..a2db7207 --- /dev/null +++ b/infrastructure/terraform/providers.tf @@ -0,0 +1,28 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "4.34.0" + } + azuread = { + source = "hashicorp/azuread" + version = "3.4.0" + } + } + backend "azurerm" { + container_name = "terraform-state" + } +} + +provider "azurerm" { + features {} +} + +provider "azurerm" { + alias = "hub" + subscription_id = var.hub_subscription_id + + features {} +} + +provider "azuread" {} diff --git a/scripts/terraform/terraform.mk b/scripts/terraform/terraform.mk index 6339b196..67ae4a1d 100644 --- a/scripts/terraform/terraform.mk +++ b/scripts/terraform/terraform.mk @@ -1,79 +1,74 @@ -# This file is for you! Edit it to implement your own Terraform make targets. - -# ============================================================================== -# Custom implementation - implementation of a make target should not exceed 5 lines of effective code. -# In most cases there should be no need to modify the existing make targets. - -TF_ENV ?= dev -STACK ?= ${stack} -TERRAFORM_STACK ?= $(or ${STACK}, infrastructure/environments/${TF_ENV}) -dir ?= ${TERRAFORM_STACK} - -terraform-init: # Initialise Terraform - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], terraform_opts|opts=[options to pass to the Terraform init command, default is none/empty] @Development - make _terraform cmd="init" \ - dir=$(or ${terraform_dir}, ${dir}) \ - opts=$(or ${terraform_opts}, ${opts}) - -terraform-plan: # Plan Terraform changes - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], terraform_opts|opts=[options to pass to the Terraform plan command, default is none/empty] @Development - make _terraform cmd="plan" \ - dir=$(or ${terraform_dir}, ${dir}) \ - opts=$(or ${terraform_opts}, ${opts}) - -terraform-apply: # Apply Terraform changes - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], terraform_opts|opts=[options to pass to the Terraform apply command, default is none/empty] @Development - make _terraform cmd="apply" \ - dir=$(or ${terraform_dir}, ${dir}) \ - opts=$(or ${terraform_opts}, ${opts}) - -terraform-destroy: # Destroy Terraform resources - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], terraform_opts|opts=[options to pass to the Terraform destroy command, default is none/empty] @Development - make _terraform \ - cmd="destroy" \ - dir=$(or ${terraform_dir}, ${dir}) \ - opts=$(or ${terraform_opts}, ${opts}) - -terraform-fmt: # Format Terraform files - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], terraform_opts|opts=[options to pass to the Terraform fmt command, default is '-recursive'] @Quality - make _terraform cmd="fmt" \ - dir=$(or ${terraform_dir}, ${dir}) \ - opts=$(or ${terraform_opts}, ${opts}) - -terraform-validate: # Validate Terraform configuration - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], terraform_opts|opts=[options to pass to the Terraform validate command, default is none/empty] @Quality - make _terraform cmd="validate" \ - dir=$(or ${terraform_dir}, ${dir}) \ - opts=$(or ${terraform_opts}, ${opts}) - -clean:: # Remove Terraform files (terraform) - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set] @Operations - make _terraform cmd="clean" \ - dir=$(or ${terraform_dir}, ${dir}) \ - opts=$(or ${terraform_opts}, ${opts}) - -_terraform: # Terraform command wrapper - mandatory: cmd=[command to execute]; optional: dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], opts=[options to pass to the Terraform command, default is none/empty] - dir=$(or ${dir}, ${TERRAFORM_STACK}) - source scripts/terraform/terraform.lib.sh - terraform-${cmd} # 'dir' and 'opts' are accessible by the function as environment variables, if set - -# ============================================================================== -# Quality checks - please DO NOT edit this section! - -terraform-shellscript-lint: # Lint all Terraform module shell scripts @Quality - for file in $$(find scripts/terraform -type f -name "*.sh"); do - file=$${file} scripts/shellscript-linter.sh - done - -# ============================================================================== -# Configuration - please DO NOT edit this section! - -terraform-install: # Install Terraform @Installation - make _install-dependency name="terraform" - -# ============================================================================== - -${VERBOSE}.SILENT: \ - _terraform \ - clean \ - terraform-apply \ - terraform-destroy \ - terraform-fmt \ - terraform-init \ - terraform-install \ - terraform-plan \ - terraform-shellscript-lint \ - terraform-validate \ +DOCKER_IMAGE= +REGION=UK South +APP_SHORT_NAME=luncs + +poc: # Target the poc environment - make poc + $(eval include infrastructure/environments/poc/variables.sh) + +dev: # Target the dev environment - make dev + $(eval include infrastructure/environments/dev/variables.sh) + +preprod: # Target the preprod environment - make preprod + $(eval include infrastructure/environments/preprod/variables.sh) + +review: # Target the review infrastructure, or a review app if PR_NUMBER is used - make review [PR_NUMBER=] + $(eval include infrastructure/environments/review/variables.sh) + $(if ${PR_NUMBER}, $(eval export TF_VAR_deploy_infra=false), $(eval export TF_VAR_deploy_container_apps=false)) + $(if ${PR_NUMBER}, $(eval export ENVIRONMENT=pr-${PR_NUMBER}), $(eval export ENVIRONMENT=review)) + +db-setup: + $(if ${TF_VAR_deploy_container_apps},, scripts/bash/db_run_job.sh ${ENVIRONMENT} ${PR_NUMBER}) + +ci: # Skip manual approvals when running in CI - make ci + $(eval AUTO_APPROVE=-auto-approve) + $(eval SKIP_AZURE_LOGIN=true) + +set-azure-account: # Set the Azure account for the environment - make set-azure-account + [ "${SKIP_AZURE_LOGIN}" != "true" ] && az account set -s ${AZURE_SUBSCRIPTION} || true + +resource-group-init: set-azure-account get-subscription-ids # Initialise the resources required by terraform - make resource-group-init + $(eval STORAGE_ACCOUNT_NAME=sa${APP_SHORT_NAME}${ENV_CONFIG}tfstate) + scripts/bash/resource_group_init.sh "${REGION}" "${HUB_SUBSCRIPTION_ID}" "${ENABLE_SOFT_DELETE}" "${ENV_CONFIG}" "${STORAGE_ACCOUNT_RG}" "${STORAGE_ACCOUNT_NAME}" "${APP_SHORT_NAME}" "${ARM_SUBSCRIPTION_ID}" + +get-subscription-ids: # Retrieve the hub subscription ID based on the subscription name in ${HUB_SUBSCRIPTION} - make get-subscription-ids + $(eval HUB_SUBSCRIPTION_ID=$(shell az account show --query id --output tsv --name ${HUB_SUBSCRIPTION})) + $(if ${ARM_SUBSCRIPTION_ID},,$(eval export ARM_SUBSCRIPTION_ID=$(shell az account show --query id --output tsv))) + +terraform-init-no-backend: # Initialise terraform modules only and update terraform lock file - make terraform-init-no-backend + rm -rf infrastructure/modules/dtos-devops-templates + git -c advice.detachedHead=false clone --depth=1 --single-branch --branch ${TERRAFORM_MODULES_REF} \ + https://github.com/NHSDigital/dtos-devops-templates.git infrastructure/modules/dtos-devops-templates + terraform -chdir=infrastructure/terraform init -upgrade -backend=false + +terraform-init: set-azure-account get-subscription-ids # Initialise Terraform - make terraform-init + $(eval STORAGE_ACCOUNT_NAME=sa${APP_SHORT_NAME}${ENV_CONFIG}tfstate) + $(eval export ARM_USE_AZUREAD=true) + + rm -rf infrastructure/modules/dtos-devops-templates + git -c advice.detachedHead=false clone --depth=1 --single-branch --branch ${TERRAFORM_MODULES_REF} \ + https://github.com/NHSDigital/dtos-devops-templates.git infrastructure/modules/dtos-devops-templates + + terraform -chdir=infrastructure/terraform init -upgrade -reconfigure \ + -backend-config=subscription_id=${HUB_SUBSCRIPTION_ID} \ + -backend-config=resource_group_name=${STORAGE_ACCOUNT_RG} \ + -backend-config=storage_account_name=${STORAGE_ACCOUNT_NAME} \ + -backend-config=key=${ENVIRONMENT}.tfstate + + $(eval export TF_VAR_app_short_name=${APP_SHORT_NAME}) +# $(eval export TF_VAR_docker_image=${DOCKER_IMAGE}:${DOCKER_IMAGE_TAG}) + $(eval export TF_VAR_environment=${ENVIRONMENT}) +# $(eval export TF_VAR_env_config=${ENV_CONFIG}) +# $(eval export TF_VAR_hub=${HUB}) +# $(eval export TF_VAR_hub_subscription_id=${HUB_SUBSCRIPTION_ID}) + +terraform-plan: terraform-init # Plan Terraform changes - make terraform-plan DOCKER_IMAGE_TAG=abcd123 + terraform -chdir=infrastructure/terraform plan -var-file ../environments/${ENV_CONFIG}/variables.tfvars + +terraform-apply: terraform-init # Apply Terraform changes - make terraform-apply DOCKER_IMAGE_TAG=abcd123 + terraform -chdir=infrastructure/terraform apply -var-file ../environments/${ENV_CONFIG}/variables.tfvars ${AUTO_APPROVE} + +terraform-destroy: terraform-init # Destroy Terraform resources - make terraform-destroy + terraform -chdir=infrastructure/terraform destroy -var-file ../environments/${ENV_CONFIG}/variables.tfvars ${AUTO_APPROVE} + +terraform-validate: terraform-init-no-backend # Validate Terraform changes - make terraform-validate + terraform -chdir=infrastructure/terraform validate