Skip to content

Commit ea78e33

Browse files
authored
Ppha 810 create slack integration into the pipeline (#452)
# What is the change? Since Pilot has gone live there has been a requirement to monitor the number of requests that have been submitted verses the number of requests submitted. To do this we need to use a container app job which interfaces with the slack app channel to fire over a payload. Below is evidence of this working on the Review environment. Please note that we will need to manually add the slack_webhook_URL to the production infra key vault for this to work. <img width="837" height="215" alt="image" src="https://github.com/user-attachments/assets/14a0b52c-7310-4af2-8386-50efeec83ba3" /> This PR was worked on by @mrlockstar and @jamiefalcus <!-- Describe the intended changes. --> # Why are we making this change? <!-- Why is this change required? What problem does it solve? -->
2 parents c05c1d1 + dbc5f5c commit ea78e33

13 files changed

Lines changed: 202 additions & 0 deletions

File tree

core

Whitespace-only changes.

infrastructure/modules/container-apps/jobs.tf

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
locals {
2+
scheduled_jobs = {
3+
collect_metrics = {
4+
cron_expression = "0 */6 * * *"
5+
environment_variables = {
6+
ENVIRONMENT = var.environment
7+
}
8+
job_short_name = "rs"
9+
job_container_args = "request_summary"
10+
}
11+
}
12+
}
13+
114
module "db_setup" {
215
source = "../dtos-devops-templates/infrastructure/modules/container-app-job"
316

@@ -25,3 +38,54 @@ module "db_setup" {
2538
]
2639

2740
}
41+
42+
module "scheduled_jobs" {
43+
source = "../dtos-devops-templates/infrastructure/modules/container-app-job"
44+
45+
for_each = local.scheduled_jobs
46+
47+
name = "${var.app_short_name}-${each.value.job_short_name}-${var.environment}"
48+
container_app_environment_id = var.container_app_environment_id
49+
resource_group_name = azurerm_resource_group.main.name
50+
51+
fetch_secrets_from_app_key_vault = var.fetch_secrets_from_app_key_vault
52+
app_key_vault_id = var.app_key_vault_id
53+
54+
container_command = ["/bin/sh", "-c"]
55+
container_args = [
56+
"python manage.py ${each.value.job_container_args}"
57+
]
58+
59+
docker_image = var.docker_image
60+
replica_retry_limit = 0
61+
user_assigned_identity_ids = flatten([
62+
[module.azure_blob_storage_identity.id],
63+
var.deploy_database_as_container ? [] : [module.db_connect_identity[0].id]
64+
])
65+
66+
environment_variables = merge(
67+
local.common_env,
68+
{
69+
"STORAGE_ACCOUNT_NAME" = module.storage.storage_account_name,
70+
"BLOB_MI_CLIENT_ID" = module.azure_blob_storage_identity.client_id,
71+
},
72+
each.value.environment_variables,
73+
var.deploy_database_as_container ? local.container_db_env : local.azure_db_env
74+
)
75+
secret_variables = merge(
76+
{ SLACK_WEBHOOK_URL = var.slack_webhook_url },
77+
var.deploy_database_as_container ? { DATABASE_PASSWORD = resource.random_password.admin_password[0].result } : {}
78+
)
79+
80+
# alerts
81+
action_group_id = var.action_group_id
82+
enable_alerting = var.enable_alerting
83+
log_analytics_workspace_id = var.log_analytics_workspace_audit_id
84+
85+
# Ensure RBAC role assignments are created before the job definition finalizes
86+
depends_on = [
87+
module.blob_storage_role_assignment,
88+
]
89+
90+
cron_expression = each.value.cron_expression
91+
}

infrastructure/modules/container-apps/variables.tf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,11 @@ variable "infra_key_vault_rg" {
196196
type = string
197197
}
198198

199+
variable "slack_webhook_url" {
200+
description = "slack_webhook_url is the URL used to send alerts to Slack. It should be stored as a secret in the infra key vault with the name 'slack-webhook-url'."
201+
type = string
202+
}
203+
199204
locals {
200205
resource_group_name = "rg-${var.app_short_name}-${var.environment}-container-app-uks"
201206

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
module "logic_app_slack_alert" {
2+
count = var.enable_alerting ? 1 : 0
3+
4+
source = "../dtos-devops-templates/infrastructure/modules/logic-app-slack-alert"
5+
6+
name = "logic-${var.app_short_name}-${var.environment}-slack-alerts"
7+
resource_group_name = azurerm_resource_group.main.name
8+
location = var.region
9+
slack_webhook_url = var.slack_webhook_url
10+
}
11+
12+
resource "azurerm_monitor_action_group" "slack" {
13+
count = var.enable_alerting ? 1 : 0
14+
15+
name = "ag-slack-${var.app_short_name}-${var.environment}-uks"
16+
resource_group_name = azurerm_resource_group.main.name
17+
short_name = "slack"
18+
19+
webhook_receiver {
20+
name = "logic-app-slack"
21+
service_uri = module.logic_app_slack_alert[0].trigger_callback_url
22+
use_common_alert_schema = true
23+
}
24+
}

infrastructure/modules/infra/variables.tf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ variable "enable_alerting" {
7373
type = bool
7474
}
7575

76+
variable "slack_webhook_url" {
77+
description = "slack_webhook_url is the URL used to send alerts to Slack. It should be stored as a secret in the infra key vault with the name 'slack-webhook-url'."
78+
type = string
79+
}
80+
7681
locals {
7782
hub_vnet_rg_name = "rg-hub-${var.hub}-uks-bootstrap"
7883
hub_vnet_name = "vnet-hub-${var.hub}-uks"

infrastructure/terraform/spoke/data.tf

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,17 @@ data "azurerm_application_insights" "app_insights" {
4949
name = "appi-${var.env_config}-uks-${var.app_short_name}"
5050
resource_group_name = local.resource_group_name
5151
}
52+
53+
data "azurerm_key_vault" "infra" {
54+
provider = azurerm.hub
55+
56+
name = local.infra_key_vault_name
57+
resource_group_name = local.infra_key_vault_rg
58+
}
59+
60+
data "azurerm_key_vault_secret" "slack_webhook_url" {
61+
name = "slack-webhook-url"
62+
key_vault_id = data.azurerm_key_vault.infra.id
63+
}
64+
65+
# git-sha-a85180497c23d742b5f92262b3b43069e44a4110

infrastructure/terraform/spoke/main.tf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ module "infra" {
2222
vnet_address_space = var.vnet_address_space
2323
cae_zone_redundancy_enabled = var.cae_zone_redundancy_enabled
2424
enable_alerting = var.enable_alerting
25+
slack_webhook_url = data.azurerm_key_vault_secret.slack_webhook_url.value
2526
}
2627

2728
module "container-apps" {
@@ -69,4 +70,5 @@ module "container-apps" {
6970
use_apex_domain = var.use_apex_domain
7071
container_memory = var.container_memory
7172
min_replicas = var.min_replicas
73+
slack_webhook_url = data.azurerm_key_vault_secret.slack_webhook_url.value
7274
}

lung_cancer_screening/questions/management/__init__.py

Whitespace-only changes.

lung_cancer_screening/questions/management/commands/__init__.py

Whitespace-only changes.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import logging
2+
import os
3+
4+
import requests
5+
from django.core.management.base import BaseCommand, CommandError
6+
from lung_cancer_screening.questions.services.request_summary import RequestSummary
7+
8+
logger = logging.getLogger(__name__)
9+
10+
class Command(BaseCommand):
11+
help = "Counts the number of submitted requests."
12+
13+
def handle(self, *args, **options):
14+
15+
logger.info("Command: Request Summary.")
16+
try:
17+
rs = RequestSummary()
18+
summary = rs.get_summary()
19+
20+
self.stdout.write(str(summary))
21+
22+
slack_webhook_url = os.environ.get("SLACK_WEBHOOK_URL")
23+
24+
if not slack_webhook_url:
25+
logger.warning("SLACK_WEBHOOK_URL is not set; skipping Slack notification.")
26+
return
27+
28+
payload = {
29+
"blocks": [
30+
{
31+
"type": "header",
32+
"text": {
33+
"type": "plain_text",
34+
"text": "Request Summary",
35+
}
36+
},
37+
{
38+
"type": "section",
39+
"fields": [
40+
{
41+
"type": "mrkdwn",
42+
"text": f"*Requests:*\n{rs.get_count()}"
43+
},
44+
{
45+
"type": "mrkdwn",
46+
"text": f"*Submitted:*\n{rs.get_submitted_count()}"
47+
}
48+
]
49+
}
50+
]
51+
}
52+
53+
response = requests.post(
54+
slack_webhook_url,
55+
json=payload,
56+
timeout=10,
57+
)
58+
response.raise_for_status()
59+
60+
logger.info("Request summary sent to Slack.")
61+
62+
except Exception as e:
63+
logger.error(e, exc_info=True)
64+
raise CommandError(e)

0 commit comments

Comments
 (0)