Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion infrastructure/instance/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions infrastructure/instance/mns_publisher.tf
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ module "mns_publisher" {
imms_base_path = strcontains(var.sub_environment, "pr-") ? "immunisation-fhir-api/FHIR/R4-${var.sub_environment}" : "immunisation-fhir-api/FHIR/R4"
lambda_kms_encryption_key_arn = data.aws_kms_key.existing_lambda_encryption_key.arn
mns_publisher_resource_name_prefix = "${local.resource_scope}-mns-outbound-events"
mns_test_notification_name_prefix = "${local.resource_scope}-mns-test-notification"
secrets_manager_policy_path = "${local.policy_path}/secret_manager.json"
account_id = data.aws_caller_identity.current.account_id
pds_environment = var.pds_environment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ resource "aws_lambda_function" "mns_publisher_lambda" {
environment {
variables = {
SPLUNK_FIREHOSE_NAME = var.splunk_firehose_stream_name
MNS_TEST_QUEUE_URL = aws_sqs_queue.mns_test_notification.url
IMMUNIZATION_ENV = var.resource_scope,
IMMUNIZATION_BASE_PATH = var.imms_base_path
PDS_ENV = var.pds_environment
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# TODO: Remove when MNS platform authorizes imms-vaccinations-1 event type
# Temporary SQS queue for testing MNS notifications until MNS HTTP endpoint is available

resource "aws_sqs_queue" "mns_test_notification" {
Comment thread
dlzhry2nhs marked this conversation as resolved.
name = "${var.mns_test_notification_name_prefix}-queue"
fifo_queue = false
message_retention_seconds = 14400
visibility_timeout_seconds = 300
}


data "aws_iam_policy_document" "mns_test_notification_sqs_policy" {
statement {
sid = "mns-test-notification-allow-lambda-access"
effect = "Allow"

principals {
type = "AWS"
identifiers = [aws_iam_role.mns_publisher_lambda_exec_role.arn]
Comment thread
dlzhry2nhs marked this conversation as resolved.
}

actions = [
"sqs:SendMessage",
]

resources = [
aws_sqs_queue.mns_test_notification.arn
]
}
}

resource "aws_sqs_queue_policy" "mns_test_notification_sqs" {
queue_url = aws_sqs_queue.mns_test_notification.id
policy = data.aws_iam_policy_document.mns_test_notification_sqs_policy.json
}

output "mns_test_queue_url" {
value = aws_sqs_queue.mns_test_notification.url
description = "URL of the MNS test notifications queue"
}

output "mns_test_queue_arn" {
value = aws_sqs_queue.mns_test_notification.arn
description = "ARN of the MNS test notifications queue"
}

5 changes: 5 additions & 0 deletions infrastructure/instance/modules/mns_publisher/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,9 @@ variable "account_id" {
variable "secrets_manager_policy_path" {
type = string
description = "Path to the IAM policy JSON template for Secrets Manager access (e.g., ./policies/secret_manager.json)."
}

variable "mns_test_notification_name_prefix" {
type = string
description = "The prefix for the name of resources for testing mns notification"
}
12 changes: 12 additions & 0 deletions infrastructure/instance/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,15 @@ output "id_sync_queue_arn" {
description = "The ARN of the ID Sync (MNS NHS Number change) SQS queue"
value = aws_sqs_queue.id_sync_queue.arn
}

# TODO: Remove when MNS platform authorizes imms-vaccinations-1 event type
Comment thread
dlzhry2nhs marked this conversation as resolved.
Outdated
# Temporary SQS queue for testing MNS notifications until MNS HTTP endpoint is available
output "mns_test_queue_url" {
value = var.mns_publisher_feature_enabled ? module.mns_publisher[0].mns_test_queue_url : null
description = "URL of the MNS test notifications queue (from mns_publisher module)"
}

output "mns_test_queue_arn" {
value = var.mns_publisher_feature_enabled ? module.mns_publisher[0].mns_test_queue_arn : null
description = "ARN of the MNS test notifications queue (from mns_publisher module)"
}
31 changes: 31 additions & 0 deletions lambdas/mns_publisher/src/mns_test_queue.py
Comment thread
edhall-nhs marked this conversation as resolved.
Outdated
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import json
import os

import boto3

from common.clients import logger

MNS_TEST_QUEUE_URL = os.getenv("MNS_TEST_QUEUE_URL")
sqs_client = boto3.client("sqs", region_name="eu-west-2")

Check warning on line 9 in lambdas/mns_publisher/src/mns_test_queue.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

AWS region should not be set with a hardcoded String

See more on https://sonarcloud.io/project/issues?id=NHSDigital_immunisation-fhir-api&issues=AZy5IbFs3aUTC8naSBp5&open=AZy5IbFs3aUTC8naSBp5&pullRequest=1268


# TODO: Remove when MNS platform authorizes imms-vaccinations-1 event type

Check warning on line 12 in lambdas/mns_publisher/src/mns_test_queue.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Complete the task associated to this "TODO" comment.

See more on https://sonarcloud.io/project/issues?id=NHSDigital_immunisation-fhir-api&issues=AZy5jqZxTzgRrYV1wwzR&open=AZy5jqZxTzgRrYV1wwzR&pullRequest=1268
# Temporary function to send MNS to SQS Queue for testing MNS notifications until MNS HTTP endpoint is available
def send_notification_to_test_queue(mns_payload: dict) -> None:
"""
Send MNS notification payload to test SQS queue as fallback.
Args: payload: MNS notification payload
"""
if not MNS_TEST_QUEUE_URL:
logger.error("MNS_TEST_QUEUE_URL environment variable is not set")
return

try:
response = sqs_client.send_message(
QueueUrl=MNS_TEST_QUEUE_URL,
MessageBody=json.dumps(mns_payload),
MessageAttributes={"source": {"StringValue": "mns-publisher-lambda", "DataType": "String"}},
)
logger.info("Successfully sent notification to test queue", extra={"message_id": response["MessageId"]})
except Exception:
logger.exception("Failed to send to test SQS queue")
14 changes: 10 additions & 4 deletions lambdas/mns_publisher/src/process_records.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
from common.api_clients.mns_setup import get_mns_service
from common.clients import logger
from create_notification import create_mns_notification
from mns_test_queue import send_notification_to_test_queue

mns_env = os.getenv("MNS_ENV", "int")
MNS_TEST_QUEUE_URL = os.getenv("MNS_TEST_QUEUE_URL")


def process_records(records: list[SQSMessage]) -> dict[str, list]:
Expand Down Expand Up @@ -62,10 +64,14 @@
},
)

mns_service.publish_notification(mns_notification_payload)
logger.info("Successfully created MNS notification", extra={"mns_notification_id": notification_id})

return None
# TODO: Remove when MNS platform authorizes imms-vaccinations-1 event type

Check warning on line 67 in lambdas/mns_publisher/src/process_records.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Complete the task associated to this "TODO" comment.

See more on https://sonarcloud.io/project/issues?id=NHSDigital_immunisation-fhir-api&issues=AZy5jqYQTzgRrYV1wwzQ&open=AZy5jqYQTzgRrYV1wwzQ&pullRequest=1268
# Temporary SQS queue for testing MNS notifications until MNS HTTP endpoint is available
if MNS_TEST_QUEUE_URL:
send_notification_to_test_queue(mns_notification_payload)
logger.info("Notification Successfully sent to SQS", extra={"notification_id": notification_id})
else:
mns_service.publish_notification(mns_notification_payload)
logger.info("Successfully created MNS notification", extra={"mns_notification_id": notification_id})


def extract_trace_ids(record: SQSMessage) -> Tuple[str, str | None]:
Expand Down
59 changes: 59 additions & 0 deletions lambdas/mns_publisher/tests/test_mns_test_queue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import json
import unittest
from unittest.mock import patch

import boto3
from moto import mock_aws

from mns_test_queue import send_notification_to_test_queue


@mock_aws
class TestMnsSqsQueue(unittest.TestCase):
Comment thread
Akol125 marked this conversation as resolved.
Outdated
def setUp(self):
self.sqs = boto3.client("sqs", region_name="eu-west-2")
response = self.sqs.create_queue(QueueName="mns-test-notifications-int")
self.queue_url = response["QueueUrl"]

self.mns_payload = {
"specversion": "1.0",
"id": "236a1d4a-5d69-4fa9-9c7f-e72bf505aa5b",
"source": "https://int.api.service.nhs.uk/immunisation-fhir-api",
"type": "imms-vaccinations-1",
"time": "20260212T174437+00:00",
"subject": "9481152782",
"dataref": "https://int.api.service.nhs.uk/immunisation-fhir-api/Immunization/d058014c-b0fd-4471-8db9-3316175eb825",
"filtering": {
"generalpractitioner": "Y12345",
"sourceorganisation": "B0C4P",
"sourceapplication": "TPP",
"subjectage": 21,
"immunisationtype": "HIB",
"action": "CREATE",
},
}

def test_send_notification_to_queue_success(self):
"""Test successful send to SQS queue with complete payload."""
with patch("mns_test_queue.MNS_TEST_QUEUE_URL", self.queue_url):
send_notification_to_test_queue(self.mns_payload)

messages = self.sqs.receive_message(
QueueUrl=self.queue_url, MaxNumberOfMessages=1, MessageAttributeNames=["All"]
)

self.assertIn("Messages", messages)
self.assertEqual(len(messages["Messages"]), 1)

# Verify message body
mns_payload = json.loads(messages["Messages"][0]["Body"])
attributes = messages["Messages"][0]["MessageAttributes"]
self.assertEqual(attributes["source"]["StringValue"], "mns-publisher-lambda")

self.assertEqual(mns_payload["subject"], "9481152782")
self.assertEqual(mns_payload["filtering"]["generalpractitioner"], "Y12345")
self.assertEqual(mns_payload["filtering"]["sourceorganisation"], "B0C4P")
self.assertEqual(mns_payload["filtering"]["sourceapplication"], "TPP")
self.assertEqual(mns_payload["filtering"]["immunisationtype"], "HIB")
self.assertEqual(mns_payload["filtering"]["action"], "CREATE")
self.assertEqual(mns_payload["filtering"]["subjectage"], 21)
Loading