Linode Interfaces: Allow specifying ExplicitNullValue for LinodeInterfaceOptions firewall ID
📝 Description
This pull request adds support for users specifying an ExplicitNullValue for the firewall_id field when creating a Linode interface. This is necessary when specifying a Linode interface with no firewall because an unspecified/implicit null value will cause the API to use the account-wide default firewall or raise an error if no default firewall has been configured.
✔️ How to Test
The following test steps assume you have pulled down this PR locally and run make install.
Unit Testing
make test-unit
Integration Testing
make test-int TEST_COMMAND=models/linode
Manual Testing
- In a linode_api4-python sandbox environment (e.g. dx-devenv), run the following:
import os
from linode_api4 import (
LinodeClient,
LinodeInterfaceOptions,
LinodeInterfacePublicOptions,
ExplicitNullValue,
LinodeInterfaceDefaultRouteOptions,
ApiError,
)
linode_client = LinodeClient(
os.getenv("LINODE_TOKEN"), base_url="https://api.linode.com/v4beta"
)
instance_index = 0
def provision_instance(interface_firewall_id):
global instance_index
result, _ = linode_client.linode.instance_create(
ltype="g6-nanode-1",
region="us-mia",
image="linode/ubuntu24.04",
label=f"pythonsdk-test-{instance_index}",
booted=False,
linode_interfaces=[
LinodeInterfaceOptions(
default_route=LinodeInterfaceDefaultRouteOptions(
ipv4=True,
ipv6=True,
),
firewall_id=interface_firewall_id,
public=LinodeInterfacePublicOptions(),
)
],
)
instance_index += 1
return result
firewall = linode_client.networking.firewall_create(
"pythonsdk-test-firewall",
rules={
"outbound_policy": "DROP",
"inbound_policy": "DROP",
"inbound": [],
"outbound": [],
},
)
# Provision an instance with no attached firewall
no_firewalls = provision_instance(ExplicitNullValue)
# Provision an instance with an implicit firewall
try:
implicit_firewall = provision_instance(None)
except ApiError as e:
implicit_firewall = "N/A"
# Provision an instance with an explicit firewall
explicit_firewall = provision_instance(firewall.id)
print(f"Firewall: {firewall.id}")
print(f"No Firewalls: {no_firewalls}")
print(f"Implicit Firewall: {implicit_firewall}")
print(f"Explicit Firewall: {explicit_firewall}")
- Ensure the output matches to the following:
Firewall:
No Firewalls: Instance:
Implicit Firewall: Instance: 78999982
Explicit Firewall: Instance: 78999983
NOTE: These values may not be correct due to a potential API issue. The POST bodies can be validated manually by adding a print(body) here: https://github.com/linode/linode_api4-python/blob/7b7f6470c8d61f46f9561b1cdaa8fee7a090d607/linode_api4/linode_client.py#L281