Repository: adamchainz/ec2-metadata

Issue:
availability_zone_id may return 404
### Python Version

3.8.10

### Package Version

2.7.0

### Description

In some cases `ec2_metadata.availability_zone_id` returns 404
```
----> 1 ec2_metadata.availability_zone_id
File functools.py:967, in __get__(self, instance, owner)
File ec2_metadata/__init__.py:87, in availability_zone_id(self)
File ec2_metadata/__init__.py:65, in _get_url(self, url, allow_404)
File requests/models.py:960, in raise_for_status(self)
HTTPError: 404 Client Error: Not Found for url: http://169.254.169.254/latest/meta-data/placement/availability-zone-id
```
I assume that all that is needed is to use `allow_404` in `_get_url`

Discussion:
adamchainz: Pending reply to https://github.com/adamchainz/ec2-metadata/issues/349#issuecomment-1061516561
arossert: @adamchainz I have replied on the issue, seems like this is only supported on instances that were created after this API was added, so there is a good reason to handle `404` in this case. 

Patch:
diff --git a/HISTORY.rst b/HISTORY.rst
index 9a6d9e6..23dbfa2 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -2,6 +2,10 @@
 History
 =======
 
+* Return ``None`` for ``availability_zone_id`` when the underlying endpoint returns HTTP 404.
+
+  Thanks to Amir Rossert in `PR #350 <https://github.com/adamchainz/ec2-metadata/pull/350>`__.
+
 2.9.0 (2022-03-25)
 ------------------
 
diff --git a/README.rst b/README.rst
index 1671b48..f435b1f 100644
--- a/README.rst
+++ b/README.rst
@@ -133,8 +133,8 @@ See AWS docs page `Retrieve the target lifecycle state through instance metadata
 
 The name of the current AZ e.g. ``'eu-west-1a'``.
 
-``availability_zone_id: str``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+``availability_zone_id: str | None``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 The unique, cross-account ID of the current AZ e.g. ``'use1-az6'``.
 See AWS docs page `AZ IDs for your AWS resources
diff --git a/src/ec2_metadata/__init__.py b/src/ec2_metadata/__init__.py
index 0db8376..520d9aa 100644
--- a/src/ec2_metadata/__init__.py
+++ b/src/ec2_metadata/__init__.py
@@ -98,8 +98,13 @@ class EC2Metadata(BaseLazyObject):
         return self._get_url(f"{self.metadata_url}placement/availability-zone").text
 
     @cached_property
-    def availability_zone_id(self) -> str:
-        return self._get_url(f"{self.metadata_url}placement/availability-zone-id").text
+    def availability_zone_id(self) -> str | None:
+        resp = self._get_url(
+            f"{self.metadata_url}placement/availability-zone-id", allow_404=True
+        )
+        if resp.status_code == 404:
+            return None
+        return resp.text
 
     @cached_property
     def ami_launch_index(self) -> int:


Test patch:
diff --git a/tests/test_ec2_metadata.py b/tests/test_ec2_metadata.py
index 24f6af1..55f701b 100644
--- a/tests/test_ec2_metadata.py
+++ b/tests/test_ec2_metadata.py
@@ -161,6 +161,14 @@ def test_availability_zone_id(em_requests_mock):
     assert ec2_metadata.availability_zone_id == "use1-az6"
 
 
+def test_availability_zone_id_none(em_requests_mock):
+    em_requests_mock.get(
+        "http://169.254.169.254/latest/meta-data/placement/availability-zone-id",
+        status_code=404,
+    )
+    assert ec2_metadata.availability_zone_id is None
+
+
 def test_domain(em_requests_mock):
     em_requests_mock.get(
         "http://169.254.169.254/latest/meta-data/services/domain",