Skip to content

Commit caca6aa

Browse files
authored
Ved 507-unsubscribe-pipeline (#715)
Unsubscribing to a notification and fixing teardown pipeline
1 parent 7130767 commit caca6aa

File tree

10 files changed

+71
-41
lines changed

10 files changed

+71
-41
lines changed

.github/dependabot.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ updates:
6060
- "/redis_sync"
6161
- "/lambdas/id_sync"
6262
- "/lambdas/shared"
63+
- "/mns_subscription"
6364
schedule:
6465
interval: "daily"
6566
open-pull-requests-limit: 1

azure/azure-pr-teardown-pipeline.yml

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,37 @@ jobs:
4545
4646
- bash: |
4747
export AWS_PROFILE=apim-dev
48-
account_id="$(aws sts get-caller-identity --query Account --output text)"
4948
5049
cd terraform
51-
terraform workspace select $(WORKSPACE)
52-
make init && make destroy aws_account_no=${account_id} environment=$(WORKSPACE)
50+
make init environment="dev" sub_environment="$WORKSPACE" bucket_name="immunisation-internal-dev-terraform-state-files"
51+
make workspace sub_environment="$WORKSPACE"
52+
53+
# Extract values from Terraform state before destroying
54+
ID_SYNC_QUEUE_ARN=$(make -s output name=id_sync_queue_arn)
55+
echo "##vso[task.setvariable variable=ID_SYNC_QUEUE_ARN]$ID_SYNC_QUEUE_ARN"
56+
displayName: "Init Terraform and extract MNS values"
57+
58+
- bash: |
59+
export AWS_PROFILE=apim-dev
60+
cd mns_subscription
61+
62+
echo "unsubscribing SQS Queue from MNS notifications."
63+
pyenv install -s 3.11.11
64+
pyenv local 3.11.11
65+
echo "Setting up poetry environment..."
66+
poetry env use 3.11
67+
poetry install --no-root
68+
69+
echo "unsubscribing SQS to MNS for notifications.."
70+
make unsubscribe
71+
displayName: "Unsubscribe MNS"
72+
env:
73+
SQS_ARN: "$(ID_SYNC_QUEUE_ARN)"
74+
75+
- bash: |
76+
export AWS_PROFILE=apim-dev
77+
78+
cd terraform
79+
make destroy environment="dev" sub_environment="$WORKSPACE" bucket_name="immunisation-internal-dev-terraform-state-files"
5380
displayName: Destroy terraform PR workspace and linked resources
54-
retryCountOnTaskFailure: 2
81+
retryCountOnTaskFailure: 2

azure/templates/post-deploy.yml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ steps:
6060
echo pr_no: $pr_no
6161
6262
cd terraform
63-
6463
make init
6564
make apply environment=${{ parameters.aws_account_type }} sub_environment=$workspace
6665
@@ -91,11 +90,8 @@ steps:
9190
poetry env use 3.11
9291
poetry install --no-root
9392
94-
echo "Setting PYTHONPATH..."
95-
export PYTHONPATH=$(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/mns_subscription
96-
9793
echo "Subscribing SQS to MNS for notifications..."
98-
poetry run python src/subscribe_mns.py
94+
make subscribe
9995
displayName: "Run MNS Subscription"
10096
workingDirectory: "$(Pipeline.Workspace)/s/$(SERVICE_NAME)/$(SERVICE_ARTIFACT_NAME)/mns_subscription"
10197
env:

mns_subscription/Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
subscribe:
2+
@PYTHONPATH=src poetry run python src/subscribe_mns.py
3+
4+
unsubscribe:
5+
@PYTHONPATH=src poetry run python src/unsubscribe_mns.py
6+
17
test:
28
@PYTHONPATH=src:tests python -m unittest
39

mns_subscription/src/mns_service.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def subscribe_notification(self) -> dict | None:
5252
if response.status_code in (200, 201):
5353
return response.json()
5454
else:
55-
MnsService.handle_response(response)
55+
MnsService.raise_error_response(response)
5656

5757
def get_subscription(self) -> dict | None:
5858
response = requests.get(MNS_URL, headers=self.request_headers, timeout=10)
@@ -70,7 +70,7 @@ def get_subscription(self) -> dict | None:
7070
return resource
7171
return None
7272
else:
73-
MnsService.handle_response(response)
73+
MnsService.raise_error_response(response)
7474

7575
def check_subscription(self) -> dict:
7676
"""
@@ -90,17 +90,17 @@ def check_subscription(self) -> dict:
9090
logging.error(f"Error ensuring subscription: {e}")
9191
raise
9292

93-
def delete_subscription(self, subscription_id: str) -> bool:
93+
def delete_subscription(self, subscription_id: str) -> str:
9494
"""Delete the subscription by ID."""
9595
url = f"{MNS_URL}/{subscription_id}"
9696
response = requests.delete(url, headers=self.request_headers, timeout=10)
97-
if response.status_code in (200, 204):
97+
if response.status_code == 204:
9898
logging.info(f"Deleted subscription {subscription_id}")
99-
return True
99+
return "Subscription Successfully Deleted..."
100100
else:
101-
MnsService.handle_response(response)
101+
MnsService.raise_error_response(response)
102102

103-
def check_delete_subcription(self):
103+
def check_delete_subscription(self):
104104
try:
105105
resource = self.get_subscription()
106106
if not resource:
@@ -116,7 +116,7 @@ def check_delete_subcription(self):
116116
return f"Error deleting subscription: {str(e)}"
117117

118118
@staticmethod
119-
def handle_response(response):
119+
def raise_error_response(response):
120120
error_mapping = {
121121
401: (TokenValidationError, "Token validation failed for the request"),
122122
400: (BadRequestError, "Bad request: Resource type or parameters incorrect"),

mns_subscription/src/mns_setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,5 @@ def get_mns_service(mns_env: str = "int"):
1919
cache=cache,
2020
)
2121

22-
logging.info("Creating MNS service...")
22+
logging.info("Authentication Initiated...")
2323
return MnsService(authenticator)

mns_subscription/src/unsubscribe_mns.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ def run_unsubscribe():
1111
if __name__ == "__main__":
1212
logging.basicConfig(level=logging.INFO)
1313
result = run_unsubscribe()
14-
logging.debug(f"Subscription Result: {result}")
14+
logging.info(f"Subscription Status: {result}")

mns_subscription/tests/test_mns_service.py

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -148,19 +148,18 @@ def test_check_subscription_creates_if_not_found(self, mock_get, mock_post):
148148

149149
@patch("mns_service.requests.delete")
150150
def test_delete_subscription_success(self, mock_delete):
151-
for code in (200, 204):
152-
mock_response = MagicMock()
153-
mock_response.status_code = code
154-
mock_delete.return_value = mock_response
155-
156-
service = MnsService(self.authenticator)
157-
result = service.delete_subscription("sub-id-123")
158-
self.assertTrue(result)
159-
mock_delete.assert_called_with(
160-
f"{MNS_URL}/sub-id-123",
161-
headers=service.request_headers,
162-
timeout=10
163-
)
151+
mock_response = MagicMock()
152+
mock_response.status_code = 204
153+
mock_delete.return_value = mock_response
154+
155+
service = MnsService(self.authenticator)
156+
result = service.delete_subscription("sub-id-123")
157+
self.assertTrue(result)
158+
mock_delete.assert_called_with(
159+
f"{MNS_URL}/sub-id-123",
160+
headers=service.request_headers,
161+
timeout=10
162+
)
164163

165164
@patch("mns_service.requests.delete")
166165
def test_delete_subscription_401(self, mock_delete):
@@ -226,7 +225,7 @@ def test_check_delete_subscription_success(self, mock_get_subscription, mock_del
226225
mock_delete_subscription.return_value = True
227226

228227
service = MnsService(self.authenticator)
229-
result = service.check_delete_subcription()
228+
result = service.check_delete_subscription()
230229
self.assertEqual(result, "Subscription successfully deleted")
231230
mock_get_subscription.assert_called_once()
232231
mock_delete_subscription.assert_called_once_with("sub-123")
@@ -236,15 +235,15 @@ def test_check_delete_subscription_no_resource(self, mock_get_subscription):
236235
# No subscription found
237236
mock_get_subscription.return_value = None
238237
service = MnsService(self.authenticator)
239-
result = service.check_delete_subcription()
238+
result = service.check_delete_subscription()
240239
self.assertEqual(result, "No matching subscription found to delete.")
241240

242241
@patch.object(MnsService, "get_subscription")
243242
def test_check_delete_subscription_missing_id(self, mock_get_subscription):
244243
# Resource with no id field
245244
mock_get_subscription.return_value = {"not_id": "not-id"}
246245
service = MnsService(self.authenticator)
247-
result = service.check_delete_subcription()
246+
result = service.check_delete_subscription()
248247
self.assertEqual(result, "Subscription resource missing 'id' field.")
249248

250249
@patch.object(MnsService, "delete_subscription")
@@ -253,7 +252,7 @@ def test_check_delete_subscription_raises(self, mock_get_subscription, mock_dele
253252
mock_get_subscription.return_value = {"id": "sub-123"}
254253
mock_delete_subscription.side_effect = Exception("Error!")
255254
service = MnsService(self.authenticator)
256-
result = service.check_delete_subcription()
255+
result = service.check_delete_subscription()
257256
self.assertTrue(result.startswith("Error deleting subscription: Error!"))
258257

259258
def mock_response(self, status_code, json_data=None):
@@ -265,23 +264,23 @@ def mock_response(self, status_code, json_data=None):
265264
def test_404_resource_found_error(self):
266265
resp = self.mock_response(404, {"resource": "Not found"})
267266
with self.assertRaises(ResourceNotFoundError) as context:
268-
MnsService.handle_response(resp)
267+
MnsService.raise_error_response(resp)
269268
self.assertIn("Subscription or Resource not found", str(context.exception))
270269
self.assertEqual(context.exception.message, "Subscription or Resource not found")
271270
self.assertEqual(context.exception.response, {"resource": "Not found"})
272271

273272
def test_400_bad_request_error(self):
274273
resp = self.mock_response(400, {"resource": "Invalid"})
275274
with self.assertRaises(BadRequestError) as context:
276-
MnsService.handle_response(resp)
275+
MnsService.raise_error_response(resp)
277276
self.assertIn("Bad request: Resource type or parameters incorrect", str(context.exception))
278277
self.assertEqual(context.exception.message, "Bad request: Resource type or parameters incorrect")
279278
self.assertEqual(context.exception.response, {"resource": "Invalid"})
280279

281280
def test_unhandled_status_code(self):
282281
resp = self.mock_response(418, {"resource": 1234})
283282
with self.assertRaises(UnhandledResponseError) as context:
284-
MnsService.handle_response(resp)
283+
MnsService.raise_error_response(resp)
285284
self.assertIn("Unhandled error: 418", str(context.exception))
286285
self.assertEqual(context.exception.response, {"resource": 1234})
287286

terraform/Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ sub_environment_dir := $(if $(findstring pr-,$(sub_environment)),pr,$(sub_enviro
66

77
tf_cmd = AWS_PROFILE=$(AWS_PROFILE) terraform
88

9-
bucket_name = $(if $(filter dev,$(environment)),immunisation-$(sub_environment),immunisation-$(environment))-terraform-state-files
9+
10+
bucket_name ?= $(if $(filter dev,$(environment)),immunisation-$(sub_environment),immunisation-$(environment))-terraform-state-files
1011

1112
tf_state = -backend-config="bucket=$(bucket_name)"
1213

1314
tf_vars = \
1415
-var="sub_environment=$(sub_environment)" \
15-
-var-file="./environments/$(environment)/$(sub_environment_dir)/variables.tfvars"
16+
-var-file=./environments/$(environment)/$(sub_environment_dir)/variables.tfvars
1617

1718
lock-provider:
1819
# Run this only when you install a new terraform provider. This will generate sha code in lock file for all platform

0 commit comments

Comments
 (0)