Skip to content

Commit 7c0aa01

Browse files
Implement fields related to LKE APL (#496)
* Add APL-related fields * Add unit test * Add integration test * Fix integration test * Add beta notice * Fix note * Make apl_enabled immutable * make format
1 parent 9488e73 commit 7c0aa01

File tree

9 files changed

+125
-9
lines changed

9 files changed

+125
-9
lines changed

linode_api4/groups/lke.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ def cluster_create(
6666
control_plane: Union[
6767
LKEClusterControlPlaneOptions, Dict[str, Any]
6868
] = None,
69+
apl_enabled: bool = False,
6970
**kwargs,
7071
):
7172
"""
@@ -100,8 +101,12 @@ def cluster_create(
100101
formatted dicts.
101102
:param kube_version: The version of Kubernetes to use
102103
:type kube_version: KubeVersion or str
103-
:param control_plane: Dict[str, Any] or LKEClusterControlPlaneRequest
104-
:type control_plane: The control plane configuration of this LKE cluster.
104+
:param control_plane: The control plane configuration of this LKE cluster.
105+
:type control_plane: Dict[str, Any] or LKEClusterControlPlaneRequest
106+
:param apl_enabled: Whether this cluster should use APL.
107+
NOTE: This endpoint is in beta and may only
108+
function if base_url is set to `https://api.linode.com/v4beta`.
109+
:type apl_enabled: bool
105110
:param kwargs: Any other arguments to pass along to the API. See the API
106111
docs for possible values.
107112
@@ -120,6 +125,10 @@ def cluster_create(
120125
}
121126
params.update(kwargs)
122127

128+
# Prevent errors for users without access to APL
129+
if apl_enabled:
130+
params["apl_enabled"] = apl_enabled
131+
123132
result = self.client.post(
124133
"/lke/clusters",
125134
data=_flatten_request_body_recursive(drop_null_keys(params)),

linode_api4/objects/linode.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1936,7 +1936,7 @@ def _serialize(self):
19361936
def _expand_placement_group_assignment(
19371937
pg: Union[
19381938
InstancePlacementGroupAssignment, "PlacementGroup", Dict[str, Any], int
1939-
]
1939+
],
19401940
) -> Optional[Dict[str, Any]]:
19411941
"""
19421942
Expands the placement group argument into a dict for use in an API request body.

linode_api4/objects/lke.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ class LKECluster(Base):
257257
"k8s_version": Property(slug_relationship=KubeVersion, mutable=True),
258258
"pools": Property(derived_class=LKENodePool),
259259
"control_plane": Property(mutable=True),
260+
"apl_enabled": Property(),
260261
}
261262

262263
def invalidate(self):
@@ -353,6 +354,36 @@ def control_plane_acl(self) -> LKEClusterControlPlaneACL:
353354

354355
return LKEClusterControlPlaneACL.from_json(self._control_plane_acl)
355356

357+
@property
358+
def apl_console_url(self) -> Optional[str]:
359+
"""
360+
Returns the URL of this cluster's APL installation if this cluster
361+
is APL-enabled, else None.
362+
363+
:returns: The URL of the APL console for this cluster.
364+
:rtype: str or None
365+
"""
366+
367+
if not self.apl_enabled:
368+
return None
369+
370+
return f"https://console.lke{self.id}.akamai-apl.net"
371+
372+
@property
373+
def apl_health_check_url(self) -> Optional[str]:
374+
"""
375+
Returns the URL of this cluster's APL health check endpoint if this cluster
376+
is APL-enabled, else None.
377+
378+
:returns: The URL of the APL console for this cluster.
379+
:rtype: str or None
380+
"""
381+
382+
if not self.apl_enabled:
383+
return None
384+
385+
return f"https://auth.lke{self.id}.akamai-apl.net/ready"
386+
356387
def node_pool_create(
357388
self,
358389
node_type: Union[Type, str],

test/fixtures/lke_clusters.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66
"label": "example-cluster",
77
"region": "ap-west",
88
"k8s_version": "1.19",
9-
"tags": []
9+
"tags": [],
10+
"apl_enabled": true
1011
}

test/fixtures/lke_clusters_18881.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@
99
"tags": [],
1010
"control_plane": {
1111
"high_availability": true
12-
}
12+
},
13+
"apl_enabled": true
1314
}

test/integration/models/image/test_image.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ def image_upload_url(test_linode_client):
3232
@pytest.fixture(scope="session")
3333
def test_uploaded_image(test_linode_client):
3434
test_image_content = (
35-
b"\x1F\x8B\x08\x08\xBD\x5C\x91\x60\x00\x03\x74\x65\x73\x74\x2E\x69"
36-
b"\x6D\x67\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00"
35+
b"\x1f\x8b\x08\x08\xbd\x5c\x91\x60\x00\x03\x74\x65\x73\x74\x2e\x69"
36+
b"\x6d\x67\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00"
3737
)
3838

3939
label = get_test_label() + "_image"

test/integration/models/lke/test_lke.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,32 @@ def lke_cluster_with_labels_and_taints(test_linode_client):
110110
cluster.delete()
111111

112112

113+
@pytest.fixture(scope="session")
114+
def lke_cluster_with_apl(test_linode_client):
115+
version = test_linode_client.lke.versions()[0]
116+
117+
region = get_region(test_linode_client, {"Kubernetes", "Disk Encryption"})
118+
119+
# NOTE: g6-dedicated-4 is the minimum APL-compatible Linode type
120+
node_pools = test_linode_client.lke.node_pool("g6-dedicated-4", 3)
121+
label = get_test_label() + "_cluster"
122+
123+
cluster = test_linode_client.lke.cluster_create(
124+
region,
125+
label,
126+
node_pools,
127+
version,
128+
control_plane=LKEClusterControlPlaneOptions(
129+
high_availability=True,
130+
),
131+
apl_enabled=True,
132+
)
133+
134+
yield cluster
135+
136+
cluster.delete()
137+
138+
113139
def get_cluster_status(cluster: LKECluster, status: str):
114140
return cluster._raw_json["status"] == status
115141

@@ -328,6 +354,19 @@ def test_lke_cluster_labels_and_taints(lke_cluster_with_labels_and_taints):
328354
assert LKENodePoolTaint.from_json(updated_taints[1]) in pool.taints
329355

330356

357+
@pytest.mark.flaky(reruns=3, reruns_delay=2)
358+
def test_lke_cluster_with_apl(lke_cluster_with_apl):
359+
assert lke_cluster_with_apl.apl_enabled == True
360+
assert (
361+
lke_cluster_with_apl.apl_console_url
362+
== f"https://console.lke{lke_cluster_with_apl.id}.akamai-apl.net"
363+
)
364+
assert (
365+
lke_cluster_with_apl.apl_health_check_url
366+
== f"https://auth.lke{lke_cluster_with_apl.id}.akamai-apl.net/ready"
367+
)
368+
369+
331370
def test_lke_types(test_linode_client):
332371
types = test_linode_client.lke.types()
333372

test/unit/objects/image_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88

99
# A minimal gzipped image that will be accepted by the API
1010
TEST_IMAGE_CONTENT = (
11-
b"\x1F\x8B\x08\x08\xBD\x5C\x91\x60\x00\x03\x74\x65\x73\x74\x2E\x69"
12-
b"\x6D\x67\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00"
11+
b"\x1f\x8b\x08\x08\xbd\x5c\x91\x60\x00\x03\x74\x65\x73\x74\x2e\x69"
12+
b"\x6d\x67\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00"
1313
)
1414

1515

test/unit/objects/lke_test.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ def test_get_cluster(self):
3939
self.assertEqual(cluster.region.id, "ap-west")
4040
self.assertEqual(cluster.k8s_version.id, "1.19")
4141
self.assertTrue(cluster.control_plane.high_availability)
42+
self.assertTrue(cluster.apl_enabled)
4243

4344
def test_get_pool(self):
4445
"""
@@ -352,6 +353,40 @@ def test_cluster_create_with_labels_and_taints(self):
352353
],
353354
}
354355

356+
def test_cluster_create_with_apl(self):
357+
"""
358+
Tests that an LKE cluster can be created with APL enabled.
359+
"""
360+
361+
with self.mock_post("lke/clusters") as m:
362+
cluster = self.client.lke.cluster_create(
363+
"us-mia",
364+
"test-aapl-cluster",
365+
[
366+
self.client.lke.node_pool(
367+
"g6-dedicated-4",
368+
3,
369+
)
370+
],
371+
"1.29",
372+
apl_enabled=True,
373+
control_plane=LKEClusterControlPlaneOptions(
374+
high_availability=True,
375+
),
376+
)
377+
378+
assert m.call_data["apl_enabled"] == True
379+
assert m.call_data["control_plane"]["high_availability"] == True
380+
381+
assert (
382+
cluster.apl_console_url == "https://console.lke18881.akamai-apl.net"
383+
)
384+
385+
assert (
386+
cluster.apl_health_check_url
387+
== "https://auth.lke18881.akamai-apl.net/ready"
388+
)
389+
355390
def test_populate_with_taints(self):
356391
"""
357392
Tests that LKENodePool correctly handles a list of LKENodePoolTaint and Dict objects.

0 commit comments

Comments
 (0)