-
Notifications
You must be signed in to change notification settings - Fork 85
TPT-4278: python-sdk: Implement support for Reserved IP for IPv4 #672
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: proj/reserved-ips
Are you sure you want to change the base?
Changes from all commits
062d9e0
220daed
3535a89
4c2a5e1
97c4a72
a99193f
3a94fc5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| import os | ||
| import sys | ||
|
|
||
| # Ensure the repo root is on sys.path so that `from test.unit.base import ...` | ||
| # works regardless of which directory pytest is invoked from. | ||
| sys.path.insert(0, os.path.dirname(__file__)) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| from typing import Any, Dict, Optional, Union | ||
| from typing import Any, Dict, List, Optional, Union | ||
|
|
||
| from linode_api4.errors import UnexpectedResponseError | ||
| from linode_api4.groups import Group | ||
|
|
@@ -17,6 +17,8 @@ | |
| Region, | ||
| ) | ||
| from linode_api4.objects.base import _flatten_request_body_recursive | ||
| from linode_api4.objects.networking import ReservedIPAddress, ReservedIPType | ||
| from linode_api4.paginated_list import PaginatedList | ||
| from linode_api4.util import drop_null_keys | ||
|
|
||
|
|
||
|
|
@@ -328,29 +330,66 @@ def ips_assign(self, region, *assignments): | |
| }, | ||
| ) | ||
|
|
||
| def ip_allocate(self, linode, public=True): | ||
| def ip_allocate( | ||
| self, | ||
| linode: Optional[Union[Instance, int]] = None, | ||
| public: bool = True, | ||
| reserved: bool = False, | ||
| region: Optional[Union[Region, str]] = None, | ||
| ) -> IPAddress: | ||
| """ | ||
| Allocates an IP to a Instance you own. Additional IPs must be requested | ||
| by opening a support ticket first. | ||
| Allocates an IP to an Instance you own, or reserves a new IP address. | ||
|
|
||
| When ``reserved`` is False (default), ``linode`` is required and an | ||
| ephemeral IP is allocated and assigned to that Instance. | ||
|
|
||
| When ``reserved`` is True, either ``region`` or ``linode`` must be | ||
| provided. Passing only ``region`` creates an unassigned reserved IP. | ||
| Passing ``linode`` (with or without ``region``) creates a reserved IP | ||
| in the Instance's region and assigns it to that Instance. | ||
|
|
||
| API Documentation: https://techdocs.akamai.com/linode-api/reference/post-allocate-ip | ||
|
|
||
| :param linode: The Instance to allocate the new IP for. | ||
| :type linode: Instance or int | ||
| :param public: If True, allocate a public IP address. Defaults to True. | ||
| :type public: bool | ||
| :param reserved: If True, reserve the new IP address. | ||
| NOTE: Reserved IP feature may not currently be available to all users. | ||
| :type reserved: bool | ||
| :param region: The region for the reserved IP (required when reserved=True and linode is not set). | ||
| NOTE: Reserved IP feature may not currently be available to all users. | ||
| :type region: str or Region | ||
|
|
||
| :returns: The new IPAddress. | ||
| :rtype: IPAddress | ||
| """ | ||
| result = self.client.post( | ||
| "/networking/ips/", | ||
| data={ | ||
| "linode_id": linode.id if isinstance(linode, Base) else linode, | ||
| "type": "ipv4", | ||
| "public": public, | ||
| }, | ||
| ) | ||
| if not reserved and linode is None: | ||
| raise ValueError("linode is required when reserved is False.") | ||
| if reserved and linode is None and region is None: | ||
| raise ValueError( | ||
| "Either linode or region must be provided when reserved is True." | ||
| ) | ||
| if not reserved and region is not None: | ||
| raise ValueError("region is only valid when reserved is True.") | ||
|
|
||
| data = { | ||
| "type": "ipv4", | ||
| "public": public, | ||
| } | ||
|
|
||
|
mgwoj marked this conversation as resolved.
|
||
| if linode is not None: | ||
| data["linode_id"] = ( | ||
| linode.id if isinstance(linode, Base) else linode | ||
| ) | ||
|
|
||
| if reserved: | ||
| data["reserved"] = True | ||
|
|
||
| if region is not None: | ||
| data["region"] = region.id if isinstance(region, Base) else region | ||
|
|
||
| result = self.client.post("/networking/ips/", data=data) | ||
|
|
||
| if not "address" in result: | ||
| raise UnexpectedResponseError( | ||
|
|
@@ -510,3 +549,76 @@ def delete_vlan(self, vlan, region): | |
| return False | ||
|
|
||
| return True | ||
|
|
||
| def reserved_ips(self, *filters) -> PaginatedList: | ||
| """ | ||
| Returns a list of reserved IPv4 addresses on your account. | ||
|
|
||
| NOTE: Reserved IP feature may not currently be available to all users. | ||
|
|
||
| API Documentation: https://techdocs.akamai.com/linode-api/reference/get-reserved-ips | ||
|
|
||
| :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 reserved IP addresses on the account. | ||
| :rtype: PaginatedList of ReservedIPAddress | ||
| """ | ||
| return self.client._get_and_filter(ReservedIPAddress, *filters) | ||
|
|
||
| def reserved_ip_create( | ||
| self, | ||
| region: Union[Region, str], | ||
| tags: Optional[List[str]] = None, | ||
| **kwargs, | ||
| ) -> ReservedIPAddress: | ||
| """ | ||
| Reserves a new IPv4 address in the given region. | ||
|
|
||
| NOTE: Reserved IP feature may not currently be available to all users. | ||
|
|
||
| API Documentation: https://techdocs.akamai.com/linode-api/reference/post-reserve-ip | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Misspelling in the address, should be: |
||
|
|
||
| :param region: The region in which to reserve the IP. | ||
| :type region: str or Region | ||
| :param tags: Tags to apply to the reserved IP. | ||
| :type tags: list of str | ||
|
|
||
| :returns: The new reserved IP address. | ||
| :rtype: ReservedIPAddress | ||
| """ | ||
| params = { | ||
| "region": region.id if isinstance(region, Region) else region, | ||
| } | ||
| if tags is not None: | ||
| params["tags"] = tags | ||
| params.update(kwargs) | ||
|
|
||
| result = self.client.post("/networking/reserved/ips", data=params) | ||
|
|
||
| if "address" not in result: | ||
| raise UnexpectedResponseError( | ||
| "Unexpected response when reserving IP address!", json=result | ||
| ) | ||
|
|
||
| return ReservedIPAddress(self.client, result["address"], result) | ||
|
|
||
| def reserved_ip_types(self, *filters) -> PaginatedList: | ||
| """ | ||
| Returns a list of reserved IP types with pricing information. | ||
|
|
||
| NOTE: Reserved IP feature may not currently be available to all users. | ||
|
|
||
| API Documentation: https://techdocs.akamai.com/linode-api/reference/get-reserved-iptypes | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| :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 reserved IP types. | ||
| :rtype: PaginatedList of ReservedIPType | ||
| """ | ||
| return self.client._get_and_filter( | ||
| ReservedIPType, *filters, endpoint="/networking/reserved/ips/types" | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -57,6 +57,20 @@ class InstanceIPNAT1To1(JSONObject): | |
| vpc_id: int = 0 | ||
|
|
||
|
|
||
| @dataclass | ||
| class ReservedIPAssignedEntity(JSONObject): | ||
| """ | ||
| Represents the entity that a reserved IP is assigned to. | ||
|
|
||
| NOTE: Reserved IP feature may not currently be available to all users. | ||
| """ | ||
|
|
||
| id: int = 0 | ||
| label: str = "" | ||
| type: str = "" | ||
| url: str = "" | ||
|
|
||
|
|
||
| class IPAddress(Base): | ||
| """ | ||
| note:: This endpoint is in beta. This will only function if base_url is set to `https://api.linode.com/v4beta`. | ||
|
|
@@ -90,6 +104,9 @@ class IPAddress(Base): | |
| "interface_id": Property(), | ||
| "region": Property(slug_relationship=Region), | ||
| "vpc_nat_1_1": Property(json_object=InstanceIPNAT1To1), | ||
| "reserved": Property(mutable=True), | ||
| "tags": Property(mutable=True, unordered=True), | ||
| "assigned_entity": Property(json_object=ReservedIPAssignedEntity), | ||
| } | ||
|
|
||
| @property | ||
|
|
@@ -156,6 +173,38 @@ def delete(self): | |
| return True | ||
|
|
||
|
|
||
| class ReservedIPAddress(Base): | ||
| """ | ||
| .. note:: This endpoint is in beta. This will only function if base_url is set to ``https://api.linode.com/v4beta``. | ||
|
|
||
| Represents a Linode Reserved IPv4 Address. | ||
|
|
||
| Update tags on a reserved IP by mutating the ``tags`` attribute and calling ``save()``. | ||
|
|
||
| NOTE: Reserved IP feature may not currently be available to all users. | ||
|
|
||
| API Documentation: https://techdocs.akamai.com/linode-api/reference/get-reserved-ip | ||
| """ | ||
|
|
||
| api_endpoint = "/networking/reserved/ips/{address}" | ||
| id_attribute = "address" | ||
|
|
||
| properties = { | ||
| "address": Property(identifier=True), | ||
| "gateway": Property(), | ||
| "linode_id": Property(), | ||
| "prefix": Property(), | ||
| "public": Property(), | ||
| "rdns": Property(), | ||
| "region": Property(slug_relationship=Region), | ||
| "reserved": Property(), | ||
| "subnet_mask": Property(), | ||
| "tags": Property(mutable=True, unordered=True), | ||
| "type": Property(), | ||
| "assigned_entity": Property(json_object=ReservedIPAssignedEntity), | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't it also include |
||
|
|
||
|
|
||
| @dataclass | ||
| class VPCIPAddressIPv6(JSONObject): | ||
| slaac_address: str = "" | ||
|
|
@@ -424,3 +473,20 @@ class NetworkTransferPrice(Base): | |
| "region_prices": Property(json_object=RegionPrice), | ||
| "transfer": Property(), | ||
| } | ||
|
|
||
|
|
||
| class ReservedIPType(Base): | ||
| """ | ||
| Represents a reserved IP type with pricing information. | ||
|
|
||
| NOTE: Reserved IP feature may not currently be available to all users. | ||
|
|
||
| API Documentation: https://techdocs.akamai.com/linode-api/reference/get-reserved-iptype | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| """ | ||
|
|
||
| properties = { | ||
| "id": Property(identifier=True), | ||
| "label": Property(), | ||
| "price": Property(json_object=Price), | ||
| "region_prices": Property(json_object=RegionPrice), | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we restrict the type for the parameters? We prefer not implementing generic types for python-sdk.
Same for the rest functions in this PR