Skip to content

Commit

Permalink
✨ Add script to check and print empty zones
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonBirchall committed Jun 26, 2024
1 parent c5c4891 commit 1fc7580
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 0 deletions.
46 changes: 46 additions & 0 deletions check_empty_zones.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import sys

import boto3


def get_aws_zones():
route53 = boto3.client("route53")
zones = []
paginator = route53.get_paginator("list_hosted_zones")
for page in paginator.paginate():
for zone in page["HostedZones"]:
zones.append((zone["Id"], zone["Name"]))
return zones


def is_zone_empty(zone_id):
route53 = boto3.client("route53")
paginator = route53.get_paginator("list_resource_record_sets")
for page in paginator.paginate(HostedZoneId=zone_id):
for record_set in page["ResourceRecordSets"]:
# Ignore NS and SOA records as they are default
if record_set["Type"] not in ["NS", "SOA"]:
return False
return True


def main():
print("Checking for empty hosted zones...")
empty_zones = []
for zone_id, zone_name in get_aws_zones():
if is_zone_empty(zone_id):
# Remove trailing dot from zone name
empty_zones.append(zone_name.rstrip("."))

if empty_zones:
print("The following hosted zones are empty:")
for zone in empty_zones:
print(f" - {zone}")
sys.exit(1)
else:
print("No empty hosted zones found.")
sys.exit(0)


if __name__ == "__main__":
main()
96 changes: 96 additions & 0 deletions tests/test_check_for_empty_zones.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
from unittest.mock import MagicMock, patch

import pytest
from check_empty_zones import get_aws_zones, is_zone_empty, main


@pytest.fixture
def mock_boto3_client():
with patch('boto3.client') as mock_client:
yield mock_client


def test_get_aws_zones(mock_boto3_client):
mock_paginator = MagicMock()
mock_paginator.paginate.return_value = [
{
'HostedZones': [
{'Id': '/hostedzone/Z1234567890ABC', 'Name': 'example.com.'},
{'Id': '/hostedzone/Z0987654321DEF', 'Name': 'test.com.'}
]
}
]
mock_boto3_client.return_value.get_paginator.return_value = mock_paginator

result = get_aws_zones()
assert result == [
('/hostedzone/Z1234567890ABC', 'example.com.'),
('/hostedzone/Z0987654321DEF', 'test.com.')
]


def test_is_zone_empty_true(mock_boto3_client):
mock_paginator = MagicMock()
mock_paginator.paginate.return_value = [
{
'ResourceRecordSets': [
{'Type': 'NS'},
{'Type': 'SOA'}
]
}
]
mock_boto3_client.return_value.get_paginator.return_value = mock_paginator

assert is_zone_empty('dummy_zone_id') == True


def test_is_zone_empty_false(mock_boto3_client):
mock_paginator = MagicMock()
mock_paginator.paginate.return_value = [
{
'ResourceRecordSets': [
{'Type': 'NS'},
{'Type': 'SOA'},
{'Type': 'A'}
]
}
]
mock_boto3_client.return_value.get_paginator.return_value = mock_paginator

assert is_zone_empty('dummy_zone_id') == False


@patch('check_empty_zones.get_aws_zones')
@patch('check_empty_zones.is_zone_empty')
def test_main_empty_zones(mock_is_zone_empty, mock_get_aws_zones, capsys):
mock_get_aws_zones.return_value = [
('/hostedzone/Z1234567890ABC', 'example.com.'),
('/hostedzone/Z0987654321DEF', 'test.com.')
]
mock_is_zone_empty.side_effect = [True, False]

with pytest.raises(SystemExit) as e:
main()

assert e.value.code == 1
captured = capsys.readouterr()
assert "The following hosted zones are empty:" in captured.out
assert " - example.com" in captured.out
assert " - test.com" not in captured.out


@patch('check_empty_zones.get_aws_zones')
@patch('check_empty_zones.is_zone_empty')
def test_main_no_empty_zones(mock_is_zone_empty, mock_get_aws_zones, capsys):
mock_get_aws_zones.return_value = [
('/hostedzone/Z1234567890ABC', 'example.com.'),
('/hostedzone/Z0987654321DEF', 'test.com.')
]
mock_is_zone_empty.return_value = False

with pytest.raises(SystemExit) as e:
main()

assert e.value.code == 0
captured = capsys.readouterr()
assert "No empty hosted zones found." in captured.out

0 comments on commit 1fc7580

Please sign in to comment.