Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
78 changes: 77 additions & 1 deletion linode_api4/groups/region.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from linode_api4.groups import Group
from linode_api4.objects import Region
from linode_api4.objects.region import RegionAvailabilityEntry
from linode_api4.objects.region import (
RegionAvailabilityEntry,
RegionVPCAvailability,
)


class RegionGroup(Group):
Expand Down Expand Up @@ -43,3 +46,76 @@ def availability(self, *filters):
return self.client._get_and_filter(
RegionAvailabilityEntry, *filters, endpoint="/regions/availability"
)

def availability_get(self, region_id):
"""
Returns availability data for a specific region.

API Documentation: https://techdocs.akamai.com/linode-api/reference/get-region-availability

:param region_id: The ID of the region to retrieve availability for.
:type region_id: str

:returns: A list of availability entries for the specified region.
:rtype: list of RegionAvailabilityEntry
"""

result = self.client.get(f"/regions/{region_id}/availability")

if result is None:
return []

return [RegionAvailabilityEntry.from_json(v) for v in result]

def vpc_availability(self, *filters):
"""
Returns VPC availability data for all regions.

NOTE: IPv6 VPCs may not currently be available to all users.

This endpoint supports pagination with the following parameters:
- page: Page number (>= 1)
- page_size: Number of items per page (25-500)

Pagination is handled automatically by PaginatedList. To configure page_size,
set it when creating the LinodeClient:

client = LinodeClient(token, page_size=100)

API Documentation: https://techdocs.akamai.com/linode-api/reference/get-regions-vpc-availability

:param filters: Any number of filters to apply to this query.
See :doc:`Filtering Collections</linode_api4/objects/filtering>`
for more details on filtering.

:returns: A list of VPC availability data for regions.
:rtype: PaginatedList of RegionVPCAvailability
"""

return self.client._get_and_filter(
RegionVPCAvailability,
*filters,
endpoint="/regions/vpc-availability",
)

def vpc_availability_get(self, region_id):
"""
Returns VPC availability data for a specific region.

NOTE: IPv6 VPCs may not currently be available to all users.

API Documentation: https://techdocs.akamai.com/linode-api/reference/get-region-vpc-availability

:param region_id: The ID of the region to retrieve VPC availability for.
:type region_id: str

:returns: VPC availability data for the specified region.
:rtype: RegionVPCAvailability
"""

result = self.client.get(f"/regions/{region_id}/vpc-availability")

if result is None:
return None

return RegionVPCAvailability.from_json(result)
38 changes: 38 additions & 0 deletions linode_api4/objects/region.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,29 @@ def availability(self) -> List["RegionAvailabilityEntry"]:

return [RegionAvailabilityEntry.from_json(v) for v in result]

@property
def vpc_availability(self) -> "RegionVPCAvailability":
"""
Returns VPC availability data for this region.

NOTE: IPv6 VPCs may not currently be available to all users.

API Documentation: https://techdocs.akamai.com/linode-api/reference/get-region-vpc-availability

:returns: VPC availability data for this region.
:rtype: RegionVPCAvailability
"""
result = self._client.get(
f"{self.api_endpoint}/vpc-availability", model=self
)

if result is None:
raise UnexpectedResponseError(
"Expected VPC availability data, got None."
)

return RegionVPCAvailability.from_json(result)


@dataclass
class RegionAvailabilityEntry(JSONObject):
Expand All @@ -75,3 +98,18 @@ class RegionAvailabilityEntry(JSONObject):
region: Optional[str] = None
plan: Optional[str] = None
available: bool = False


@dataclass
class RegionVPCAvailability(JSONObject):
"""
Represents the VPC availability data for a region.

API Documentation: https://techdocs.akamai.com/linode-api/reference/get-regions-vpc-availability

NOTE: IPv6 VPCs may not currently be available to all users.
"""

region: Optional[str] = None
available: bool = False
available_ipv6_prefix_lengths: Optional[List[int]] = None
5 changes: 5 additions & 0 deletions test/fixtures/regions_us-east_vpc-availability.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"region": "us-east",
"available": true,
"available_ipv6_prefix_lengths": [52, 60]
}
132 changes: 132 additions & 0 deletions test/fixtures/regions_vpc-availability.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
{
"data": [
{
"region": "us-east",
"available": true,
"available_ipv6_prefix_lengths": [52, 48]
},
{
"region": "us-west",
"available": true,
"available_ipv6_prefix_lengths": [56, 52, 48]
},
{
"region": "nl-ams",
"available": true,
"available_ipv6_prefix_lengths": []
},
{
"region": "us-ord",
"available": true,
"available_ipv6_prefix_lengths": []
},
{
"region": "us-iad",
"available": true,
"available_ipv6_prefix_lengths": []
},
{
"region": "fr-par",
"available": true,
"available_ipv6_prefix_lengths": []
},
{
"region": "us-sea",
"available": true,
"available_ipv6_prefix_lengths": []
},
{
"region": "br-gru",
"available": true,
"available_ipv6_prefix_lengths": []
},
{
"region": "se-sto",
"available": true,
"available_ipv6_prefix_lengths": []
},
{
"region": "es-mad",
"available": true,
"available_ipv6_prefix_lengths": []
},
{
"region": "in-maa",
"available": true,
"available_ipv6_prefix_lengths": []
},
{
"region": "jp-osa",
"available": true,
"available_ipv6_prefix_lengths": []
},
{
"region": "it-mil",
"available": true,
"available_ipv6_prefix_lengths": []
},
{
"region": "us-mia",
"available": true,
"available_ipv6_prefix_lengths": []
},
{
"region": "id-cgk",
"available": true,
"available_ipv6_prefix_lengths": []
},
{
"region": "us-lax",
"available": true,
"available_ipv6_prefix_lengths": []
},
{
"region": "gb-lon",
"available": true,
"available_ipv6_prefix_lengths": []
},
{
"region": "au-mel",
"available": true,
"available_ipv6_prefix_lengths": []
},
{
"region": "in-bom-2",
"available": true,
"available_ipv6_prefix_lengths": []
},
{
"region": "de-fra-2",
"available": true,
"available_ipv6_prefix_lengths": []
},
{
"region": "sg-sin-2",
"available": true,
"available_ipv6_prefix_lengths": []
},
{
"region": "jp-tyo-3",
"available": true,
"available_ipv6_prefix_lengths": []
},
{
"region": "fr-par-2",
"available": true,
"available_ipv6_prefix_lengths": []
},
{
"region": "ca-central",
"available": false,
"available_ipv6_prefix_lengths": []
},
{
"region": "ap-southeast",
"available": false,
"available_ipv6_prefix_lengths": []
}
],
"page": 1,
"pages": 2,
"results": 50
}
108 changes: 108 additions & 0 deletions test/integration/models/region/test_region.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import pytest

from linode_api4.objects import Region


@pytest.mark.smoke
def test_list_regions_vpc_availability(test_linode_client):
"""
Test listing VPC availability for all regions.
"""
client = test_linode_client

vpc_availability = client.regions.vpc_availability()

assert len(vpc_availability) > 0

for entry in vpc_availability:
assert entry.region is not None
assert len(entry.region) > 0
assert entry.available is not None
assert isinstance(entry.available, bool)
# available_ipv6_prefix_lengths may be empty list but should exist
assert entry.available_ipv6_prefix_lengths is not None
assert isinstance(entry.available_ipv6_prefix_lengths, list)


@pytest.mark.smoke
def test_get_region_vpc_availability_via_group(test_linode_client):
"""
Test getting VPC availability for a specific region via RegionGroup.
"""
client = test_linode_client

# Get the first available region
regions = client.regions()
assert len(regions) > 0
test_region_id = regions[0].id

vpc_avail = client.regions.vpc_availability_get(test_region_id)

assert vpc_avail is not None
assert vpc_avail.region == test_region_id
assert vpc_avail.available is not None
assert isinstance(vpc_avail.available, bool)
assert vpc_avail.available_ipv6_prefix_lengths is not None
assert isinstance(vpc_avail.available_ipv6_prefix_lengths, list)


@pytest.mark.smoke
def test_get_region_vpc_availability_via_object(test_linode_client):
"""
Test getting VPC availability via the Region object property.
"""
client = test_linode_client

# Get the first available region
regions = client.regions()
assert len(regions) > 0
test_region_id = regions[0].id

region = Region(client, test_region_id)
vpc_avail = region.vpc_availability

assert vpc_avail is not None
assert vpc_avail.region == test_region_id
assert vpc_avail.available is not None
assert isinstance(vpc_avail.available, bool)
assert vpc_avail.available_ipv6_prefix_lengths is not None
assert isinstance(vpc_avail.available_ipv6_prefix_lengths, list)


@pytest.mark.smoke
def test_get_region_availability_via_group(test_linode_client):
"""
Test getting availability for a specific region via RegionGroup.
"""
client = test_linode_client

# Get the first available region
regions = client.regions()
assert len(regions) > 0
test_region_id = regions[0].id

avail_entries = client.regions.availability_get(test_region_id)

assert len(avail_entries) > 0

for entry in avail_entries:
assert entry.region == test_region_id
assert entry.plan is not None
assert len(entry.plan) > 0
assert entry.available is not None
assert isinstance(entry.available, bool)


def test_vpc_availability_available_regions(test_linode_client):
"""
Test that some regions have VPC availability enabled.
"""
client = test_linode_client

vpc_availability = client.regions.vpc_availability()

# Filter for regions where VPC is available
available_regions = [v for v in vpc_availability if v.available]

# There should be at least some regions with VPC available
assert len(available_regions) > 0
Loading