Skip to content

Commit 7af9400

Browse files
mawilk90dependabot[bot]mgwoj
authored
TPT-4285: Implement integration tests for ReservedIP for IPv4 (#688)
* build(deps): bump actions/dependency-review-action from 4 to 5 (#695) Bumps [actions/dependency-review-action](https://github.com/actions/dependency-review-action) from 4 to 5. - [Release notes](https://github.com/actions/dependency-review-action/releases) - [Commits](actions/dependency-review-action@v4...v5) --- updated-dependencies: - dependency-name: actions/dependency-review-action dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Change assignments type from dict to list (#687) * TPT-4278: python-sdk: Implement support for Reserved IP for IPv4 (#672) * TPT-4278 python-sdk: Implement support for Reserved IP for IPv4 # Conflicts: # conftest.py # linode_api4/groups/networking.py # linode_api4/groups/tag.py # linode_api4/objects/networking.py # test/unit/groups/networking_test.py * TPT-4278: python-sdk: Implement support for Reserved IP for IPv4 * Create int tests for Reserved IPs networking endpoints * Create int tests for Reserved IPs: types, allocate * Create int tests for Reserved IPs: ephemeral * Create int tests for Reserved IPs: linode instances * Move fixtures for reserved IPs into conftest * Create int tests for Reserved IPs: linode interfaces * Create int tests for Reserved IPs: nodebalancers * Create int tests for Reserved IPs: tags * Refactor * Update tests after API changes on DevCloud * Create int tests for Reserved IPs: tags #2 * Linter fix * Linter fix * Remove pytest.ini * Remove unused assertions after API Team clarifications * Use reservedIP's region for NB * Refactor * Address Copilot remarks * Linter fix * Revert capabilities' changes in get_regions * Linter fixes * Address Copilot remarks * Address PR remarks * Use try-finally to delete resources in case of fail --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Michal Wojcik <32574975+mgwoj@users.noreply.github.com> Co-authored-by: Michal Wojcik <miwojci@akamai.com>
1 parent 0ef2ee6 commit 7af9400

9 files changed

Lines changed: 447 additions & 8 deletions

File tree

.github/workflows/dependency-review.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ jobs:
1313
- name: 'Checkout repository'
1414
uses: actions/checkout@v6
1515
- name: 'Dependency Review'
16-
uses: actions/dependency-review-action@v4
16+
uses: actions/dependency-review-action@v5
1717
with:
1818
comment-summary-in-pr: on-failure

linode_api4/groups/networking.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -491,10 +491,10 @@ def ip_addresses_assign(self, assignments, region):
491491
:param assignments: Any number of assignments to make. See
492492
:any:`IPAddress.to` for details on how to construct
493493
assignments.
494-
:type assignments: dct
494+
:type assignments: list
495495
"""
496496

497-
for a in assignments["assignments"]:
497+
for a in assignments:
498498
if not "address" in a or not "linode_id" in a:
499499
raise ValueError("Invalid assignment: {}".format(a))
500500

test/integration/conftest.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
from requests.exceptions import ConnectionError, RequestException
1717

1818
from linode_api4 import (
19+
Instance,
1920
InterfaceGeneration,
21+
IPAddress,
2022
LinodeInterfaceDefaultRouteOptions,
2123
LinodeInterfaceOptions,
2224
LinodeInterfacePublicOptions,
@@ -25,6 +27,7 @@
2527
PlacementGroupPolicy,
2628
PlacementGroupType,
2729
PostgreSQLDatabase,
30+
ReservedIPAddress,
2831
)
2932
from linode_api4.errors import ApiError
3033
from linode_api4.linode_client import LinodeClient, MonitorClient
@@ -727,3 +730,48 @@ def test_monitor_client(get_monitor_token_for_db_entities):
727730
)
728731

729732
return client, entity_ids
733+
734+
735+
@pytest.fixture
736+
def create_reserved_ip(test_linode_client):
737+
client = test_linode_client
738+
region = get_region(client, {"Linodes", "Cloud Firewall"}, site_type="core")
739+
reserved_ip = client.networking.reserved_ip_create(
740+
region=region, tags=["test"]
741+
)
742+
743+
yield reserved_ip
744+
745+
# Delete only if IP exists (some tests delete it earlier)
746+
if client.networking.reserved_ips(
747+
ReservedIPAddress.address == reserved_ip.address
748+
):
749+
reserved_ip.delete()
750+
751+
752+
@pytest.fixture
753+
def create_reserved_ip_assigned(test_linode_client, create_linode):
754+
client = test_linode_client
755+
linode = create_linode
756+
reserved_ip = client.networking.reserved_ip_create(
757+
region=linode.region,
758+
tags=["test", "assigned"],
759+
)
760+
761+
client.networking.ip_addresses_assign(
762+
assignments=[{"address": reserved_ip.address, "linode_id": linode.id}],
763+
region=linode.region,
764+
)
765+
766+
linode = client.load(Instance, linode.id)
767+
reserved_ip = test_linode_client.load(
768+
ReservedIPAddress, reserved_ip.address
769+
)
770+
771+
yield linode, reserved_ip
772+
773+
# Delete assigned IP address completely
774+
if address := client.networking.ips(
775+
IPAddress.address == reserved_ip.address
776+
):
777+
address[0].delete()

test/integration/models/linode/interfaces/test_interfaces.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import copy
22
import ipaddress
3+
from test.integration.helpers import get_test_label
34

45
import pytest
56

67
from linode_api4 import (
78
ApiError,
89
Instance,
10+
InterfaceGeneration,
911
LinodeInterface,
1012
LinodeInterfaceDefaultRouteOptions,
13+
LinodeInterfaceOptions,
1114
LinodeInterfacePublicIPv4AddressOptions,
1215
LinodeInterfacePublicIPv4Options,
1316
LinodeInterfacePublicIPv6Options,
@@ -18,9 +21,54 @@
1821
LinodeInterfaceVPCIPv4Options,
1922
LinodeInterfaceVPCIPv4RangeOptions,
2023
LinodeInterfaceVPCOptions,
24+
ReservedIPAddress,
2125
)
2226

2327

28+
def build_interface_public_ipv4(firewall, ip_address):
29+
return LinodeInterfaceOptions(
30+
firewall_id=firewall,
31+
default_route=LinodeInterfaceDefaultRouteOptions(
32+
ipv4=True,
33+
),
34+
public=LinodeInterfacePublicOptions(
35+
ipv4=LinodeInterfacePublicIPv4Options(
36+
addresses=[
37+
LinodeInterfacePublicIPv4AddressOptions(
38+
address=ip_address, primary=True
39+
)
40+
],
41+
),
42+
),
43+
)
44+
45+
46+
def create_linode_with_legacy_config(client, ip_address, label, firewall):
47+
linode, _ = client.linode.instance_create(
48+
"g6-nanode-1",
49+
ip_address.region,
50+
image="linode/debian12",
51+
label=label,
52+
firewall=firewall,
53+
interface_generation=InterfaceGeneration.LEGACY_CONFIG,
54+
ipv4=[ip_address.address],
55+
)
56+
return linode
57+
58+
59+
def create_linode_with_standard_interfaces(client, ip_address, label, firewall):
60+
interface = build_interface_public_ipv4(firewall.id, ip_address.address)
61+
linode, _ = client.linode.instance_create(
62+
"g6-nanode-1",
63+
ip_address.region,
64+
image="linode/debian12",
65+
label=label,
66+
interface_generation=InterfaceGeneration.LINODE,
67+
interfaces=[interface],
68+
)
69+
return linode
70+
71+
2472
def test_linode_create_with_linode_interfaces(
2573
create_vpc_with_subnet,
2674
linode_with_linode_interfaces,
@@ -359,3 +407,42 @@ def test_linode_interface_firewalls(e2e_test_firewall, linode_interface_public):
359407
firewall = firewalls[0]
360408
assert firewall.id == e2e_test_firewall.id
361409
assert firewall.label == e2e_test_firewall.label
410+
411+
412+
@pytest.mark.parametrize(
413+
"create_linode_fn",
414+
[create_linode_with_legacy_config, create_linode_with_standard_interfaces],
415+
ids=["legacy_config", "standard_interfaces"],
416+
)
417+
def test_linode_interfaces_with_reserved_ips(
418+
test_linode_client, e2e_test_firewall, create_reserved_ip, create_linode_fn
419+
):
420+
client = test_linode_client
421+
reserved_ip = create_reserved_ip
422+
label = get_test_label(length=8)
423+
424+
linode = create_linode_fn(client, reserved_ip, label, e2e_test_firewall)
425+
426+
try:
427+
linode_ips = linode.ips.ipv4.public
428+
assert len(linode_ips) == 1
429+
assert linode_ips[0].address == reserved_ip.address
430+
assert linode_ips[0].reserved == True
431+
assert linode_ips[0].linode_id == linode.id
432+
assert linode_ips[0].assigned_entity.id == linode.id
433+
assert linode_ips[0].assigned_entity.type == "linode"
434+
assert linode_ips[0].assigned_entity.label == linode.label
435+
assert (
436+
linode_ips[0].assigned_entity.url
437+
== f"/v4/linode/instances/{linode.id}"
438+
)
439+
finally:
440+
linode.delete()
441+
442+
reserved_ips_list = client.networking.reserved_ips(
443+
ReservedIPAddress.address == reserved_ip.address
444+
)
445+
assert len(reserved_ips_list) == 1
446+
assert reserved_ips_list[0].reserved == True
447+
assert reserved_ips_list[0].linode_id is None
448+
assert reserved_ips_list[0].assigned_entity is None

test/integration/models/linode/test_linode.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
Instance,
2020
InterfaceGeneration,
2121
LinodeInterface,
22+
ReservedIPAddress,
2223
Type,
2324
)
2425
from linode_api4.objects.linode import InstanceDiskEncryptionType, MigrationType
@@ -1156,3 +1157,42 @@ def test_update_linode_maintenance_policy(create_linode, test_linode_client):
11561157
linode.invalidate()
11571158
assert result
11581159
assert linode.maintenance_policy_id == non_default_policy.slug
1160+
1161+
1162+
def test_update_linode_with_reserved_ip_in_address(
1163+
test_linode_client, e2e_test_firewall, create_reserved_ip
1164+
):
1165+
label = get_test_label(length=8)
1166+
client = test_linode_client
1167+
reserved_ip = create_reserved_ip
1168+
1169+
linode, _ = client.linode.instance_create(
1170+
"g6-nanode-1",
1171+
reserved_ip.region,
1172+
image="linode/debian12",
1173+
label=label,
1174+
firewall=e2e_test_firewall,
1175+
)
1176+
1177+
linode_ips = linode.ips.ipv4.public
1178+
assert len(linode_ips) == 1
1179+
assert linode_ips[0].address != reserved_ip.address
1180+
1181+
linode.ip_allocate(True, reserved_ip.address)
1182+
delattr(linode, "_ips")
1183+
linode_ips = linode.ips.ipv4.public
1184+
assert len(linode_ips) == 2
1185+
assert reserved_ip.address in [ip.address for ip in linode_ips]
1186+
1187+
reserved_ip = client.networking.reserved_ips(
1188+
ReservedIPAddress.address == reserved_ip.address
1189+
)[0]
1190+
assert reserved_ip.linode_id == linode.id
1191+
assert reserved_ip.assigned_entity.id == linode.id
1192+
assert reserved_ip.assigned_entity.type == "linode"
1193+
assert reserved_ip.assigned_entity.label == linode.label
1194+
assert (
1195+
reserved_ip.assigned_entity.url == f"/v4/linode/instances/{linode.id}"
1196+
)
1197+
1198+
linode.delete()

0 commit comments

Comments
 (0)