Skip to content

Commit d432d5e

Browse files
Merge pull request #522 from linode/dev
Release v5.29.0
2 parents e6cc986 + 95970e4 commit d432d5e

29 files changed

+748
-8
lines changed

linode_api4/groups/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from .image import *
99
from .linode import *
1010
from .lke import *
11+
from .lke_tier import *
1112
from .longview import *
1213
from .networking import *
1314
from .nodebalancer import *

linode_api4/groups/lke.py

+24-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
from typing import Any, Dict, Union
1+
from typing import Any, Dict, Optional, Union
22

33
from linode_api4.errors import UnexpectedResponseError
44
from linode_api4.groups import Group
5+
from linode_api4.groups.lke_tier import LKETierGroup
56
from linode_api4.objects import (
67
KubeVersion,
78
LKECluster,
@@ -67,6 +68,7 @@ def cluster_create(
6768
LKEClusterControlPlaneOptions, Dict[str, Any]
6869
] = None,
6970
apl_enabled: bool = False,
71+
tier: Optional[str] = None,
7072
**kwargs,
7173
):
7274
"""
@@ -104,9 +106,13 @@ def cluster_create(
104106
:param control_plane: The control plane configuration of this LKE cluster.
105107
:type control_plane: Dict[str, Any] or LKEClusterControlPlaneRequest
106108
:param apl_enabled: Whether this cluster should use APL.
107-
NOTE: This endpoint is in beta and may only
109+
NOTE: This field is in beta and may only
108110
function if base_url is set to `https://api.linode.com/v4beta`.
109111
:type apl_enabled: bool
112+
:param tier: The tier of LKE cluster to create.
113+
NOTE: This field is in beta and may only
114+
function if base_url is set to `https://api.linode.com/v4beta`.
115+
:type tier: str
110116
:param kwargs: Any other arguments to pass along to the API. See the API
111117
docs for possible values.
112118
@@ -122,6 +128,7 @@ def cluster_create(
122128
node_pools if isinstance(node_pools, list) else [node_pools]
123129
),
124130
"control_plane": control_plane,
131+
"tier": tier,
125132
}
126133
params.update(kwargs)
127134

@@ -183,3 +190,18 @@ def types(self, *filters):
183190
return self.client._get_and_filter(
184191
LKEType, *filters, endpoint="/lke/types"
185192
)
193+
194+
def tier(self, id: str) -> LKETierGroup:
195+
"""
196+
Returns an object representing the LKE tier API path.
197+
198+
NOTE: LKE tiers may not currently be available to all users.
199+
200+
:param id: The ID of the tier.
201+
:type id: str
202+
203+
:returns: An object representing the LKE tier API path.
204+
:rtype: LKETier
205+
"""
206+
207+
return LKETierGroup(self.client, id)

linode_api4/groups/lke_tier.py

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from linode_api4.groups import Group
2+
from linode_api4.objects import TieredKubeVersion
3+
4+
5+
class LKETierGroup(Group):
6+
"""
7+
Encapsulates methods related to a specific LKE tier. This
8+
should not be instantiated on its own, but should instead be used through
9+
an instance of :any:`LinodeClient`::
10+
11+
client = LinodeClient(token)
12+
instances = client.lke.tier("standard") # use the LKETierGroup
13+
14+
This group contains all features beneath the `/lke/tiers/{tier}` group in the API v4.
15+
"""
16+
17+
def __init__(self, client: "LinodeClient", tier: str):
18+
super().__init__(client)
19+
self.tier = tier
20+
21+
def versions(self, *filters):
22+
"""
23+
Returns a paginated list of versions for this tier matching the given filters.
24+
25+
API Documentation: Not Yet Available
26+
27+
:param filters: Any number of filters to apply to this query.
28+
See :doc:`Filtering Collections</linode_api4/objects/filtering>`
29+
for more details on filtering.
30+
31+
:returns: A paginated list of kube versions that match the query.
32+
:rtype: PaginatedList of TieredKubeVersion
33+
"""
34+
35+
return self.client._get_and_filter(
36+
TieredKubeVersion,
37+
endpoint=f"/lke/tiers/{self.tier}/versions",
38+
parent_id=self.tier,
39+
*filters,
40+
)

linode_api4/groups/object_storage.py

+19
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from linode_api4 import (
99
ObjectStorageEndpoint,
1010
ObjectStorageEndpointType,
11+
ObjectStorageType,
1112
PaginatedList,
1213
)
1314
from linode_api4.errors import UnexpectedResponseError
@@ -70,6 +71,24 @@ def keys(self, *filters):
7071
"""
7172
return self.client._get_and_filter(ObjectStorageKeys, *filters)
7273

74+
def types(self, *filters):
75+
"""
76+
Returns a paginated list of Object Storage Types.
77+
78+
API Documentation: https://techdocs.akamai.com/linode-api/reference/get-object-storage-types
79+
80+
:param filters: Any number of filters to apply to this query.
81+
See :doc:`Filtering Collections</linode_api4/objects/filtering>`
82+
for more details on filtering.
83+
84+
:returns: A Paginated List of Object Storage types that match the query.
85+
:rtype: PaginatedList of ObjectStorageType
86+
"""
87+
88+
return self.client._get_and_filter(
89+
ObjectStorageType, *filters, endpoint="/object-storage/types"
90+
)
91+
7392
def keys_create(
7493
self,
7594
label: str,

linode_api4/linode_client.py

+14-3
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,13 @@ def volume_create(self, label, region=None, linode=None, size=20, **kwargs):
455455
)
456456

457457
# helper functions
458-
def _get_and_filter(self, obj_type, *filters, endpoint=None):
458+
def _get_and_filter(
459+
self,
460+
obj_type,
461+
*filters,
462+
endpoint=None,
463+
parent_id=None,
464+
):
459465
parsed_filters = None
460466
if filters:
461467
if len(filters) > 1:
@@ -467,8 +473,13 @@ def _get_and_filter(self, obj_type, *filters, endpoint=None):
467473

468474
# Use sepcified endpoint
469475
if endpoint:
470-
return self._get_objects(endpoint, obj_type, filters=parsed_filters)
476+
return self._get_objects(
477+
endpoint, obj_type, parent_id=parent_id, filters=parsed_filters
478+
)
471479
else:
472480
return self._get_objects(
473-
obj_type.api_list(), obj_type, filters=parsed_filters
481+
obj_type.api_list(),
482+
obj_type,
483+
parent_id=parent_id,
484+
filters=parsed_filters,
474485
)

linode_api4/objects/database.py

+48
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,30 @@ def invalidate(self):
265265

266266
Base.invalidate(self)
267267

268+
def suspend(self):
269+
"""
270+
Suspend a MySQL Managed Database, releasing idle resources and keeping only necessary data.
271+
272+
API documentation: https://techdocs.akamai.com/linode-api/reference/suspend-databases-mysql-instance
273+
"""
274+
self._client.post(
275+
"{}/suspend".format(MySQLDatabase.api_endpoint), model=self
276+
)
277+
278+
return self.invalidate()
279+
280+
def resume(self):
281+
"""
282+
Resume a suspended MySQL Managed Database.
283+
284+
API documentation: https://techdocs.akamai.com/linode-api/reference/resume-databases-mysql-instance
285+
"""
286+
self._client.post(
287+
"{}/resume".format(MySQLDatabase.api_endpoint), model=self
288+
)
289+
290+
return self.invalidate()
291+
268292

269293
class PostgreSQLDatabase(Base):
270294
"""
@@ -405,6 +429,30 @@ def invalidate(self):
405429

406430
Base.invalidate(self)
407431

432+
def suspend(self):
433+
"""
434+
Suspend a PostgreSQL Managed Database, releasing idle resources and keeping only necessary data.
435+
436+
API documentation: https://techdocs.akamai.com/linode-api/reference/suspend-databases-postgre-sql-instance
437+
"""
438+
self._client.post(
439+
"{}/suspend".format(PostgreSQLDatabase.api_endpoint), model=self
440+
)
441+
442+
return self.invalidate()
443+
444+
def resume(self):
445+
"""
446+
Resume a suspended PostgreSQL Managed Database.
447+
448+
API documentation: https://techdocs.akamai.com/linode-api/reference/resume-databases-postgre-sql-instance
449+
"""
450+
self._client.post(
451+
"{}/resume".format(PostgreSQLDatabase.api_endpoint), model=self
452+
)
453+
454+
return self.invalidate()
455+
408456

409457
ENGINE_TYPE_TRANSLATION = {
410458
"mysql": MySQLDatabase,

linode_api4/objects/lke.py

+48-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
Region,
1515
Type,
1616
)
17+
from linode_api4.objects.base import _flatten_request_body_recursive
1718
from linode_api4.util import drop_null_keys
1819

1920

@@ -49,6 +50,26 @@ class KubeVersion(Base):
4950
}
5051

5152

53+
class TieredKubeVersion(DerivedBase):
54+
"""
55+
A TieredKubeVersion is a version of Kubernetes that is specific to a certain LKE tier.
56+
57+
NOTE: LKE tiers may not currently be available to all users.
58+
59+
API Documentation: https://techdocs.akamai.com/linode-api/reference/get-lke-version
60+
"""
61+
62+
api_endpoint = "/lke/tiers/{tier}/versions/{id}"
63+
parent_id_name = "tier"
64+
id_attribute = "id"
65+
derived_url_path = "versions"
66+
67+
properties = {
68+
"id": Property(identifier=True),
69+
"tier": Property(identifier=True),
70+
}
71+
72+
5273
@dataclass
5374
class LKENodePoolTaint(JSONObject):
5475
"""
@@ -154,6 +175,8 @@ class LKENodePool(DerivedBase):
154175
An LKE Node Pool describes a pool of Linode Instances that exist within an
155176
LKE Cluster.
156177
178+
NOTE: The k8s_version and update_strategy fields are only available for LKE Enterprise clusters.
179+
157180
API Documentation: https://techdocs.akamai.com/linode-api/reference/get-lke-node-pool
158181
"""
159182

@@ -175,6 +198,12 @@ class LKENodePool(DerivedBase):
175198
"tags": Property(mutable=True, unordered=True),
176199
"labels": Property(mutable=True),
177200
"taints": Property(mutable=True),
201+
# Enterprise-specific properties
202+
# Ideally we would use slug_relationship=TieredKubeVersion here, but
203+
# it isn't possible without an extra request because the tier is not
204+
# directly exposed in the node pool response.
205+
"k8s_version": Property(mutable=True),
206+
"update_strategy": Property(mutable=True),
178207
}
179208

180209
def _parse_raw_node(
@@ -255,6 +284,7 @@ class LKECluster(Base):
255284
"pools": Property(derived_class=LKENodePool),
256285
"control_plane": Property(mutable=True),
257286
"apl_enabled": Property(),
287+
"tier": Property(),
258288
}
259289

260290
def invalidate(self):
@@ -385,6 +415,10 @@ def node_pool_create(
385415
node_count: int,
386416
labels: Optional[Dict[str, str]] = None,
387417
taints: List[Union[LKENodePoolTaint, Dict[str, Any]]] = None,
418+
k8s_version: Optional[
419+
Union[str, KubeVersion, TieredKubeVersion]
420+
] = None,
421+
update_strategy: Optional[str] = None,
388422
**kwargs,
389423
):
390424
"""
@@ -399,7 +433,13 @@ def node_pool_create(
399433
:param labels: A dict mapping labels to their values to apply to this pool.
400434
:type labels: Dict[str, str]
401435
:param taints: A list of taints to apply to this pool.
402-
:type taints: List of :any:`LKENodePoolTaint` or dict
436+
:type taints: List of :any:`LKENodePoolTaint` or dict.
437+
:param k8s_version: The Kubernetes version to use for this pool.
438+
NOTE: This field is specific to enterprise clusters.
439+
:type k8s_version: str, KubeVersion, or TieredKubeVersion
440+
:param update_strategy: The strategy to use when updating this node pool.
441+
NOTE: This field is specific to enterprise clusters.
442+
:type update_strategy: str
403443
:param kwargs: Any other arguments to pass to the API. See the API docs
404444
for possible values.
405445
@@ -409,6 +449,10 @@ def node_pool_create(
409449
params = {
410450
"type": node_type,
411451
"count": node_count,
452+
"labels": labels,
453+
"taints": taints,
454+
"k8s_version": k8s_version,
455+
"update_strategy": update_strategy,
412456
}
413457

414458
if labels is not None:
@@ -420,7 +464,9 @@ def node_pool_create(
420464
params.update(kwargs)
421465

422466
result = self._client.post(
423-
"{}/pools".format(LKECluster.api_endpoint), model=self, data=params
467+
"{}/pools".format(LKECluster.api_endpoint),
468+
model=self,
469+
data=drop_null_keys(_flatten_request_body_recursive(params)),
424470
)
425471
self.invalidate()
426472

linode_api4/objects/networking.py

+31
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,37 @@ def get_rules(self):
244244
"{}/rules".format(self.api_endpoint), model=self
245245
)
246246

247+
@property
248+
def rule_versions(self):
249+
"""
250+
Gets the JSON rule versions for this Firewall.
251+
252+
API Documentation: https://techdocs.akamai.com/linode-api/reference/get-firewall-rule-versions
253+
254+
:returns: Lists the current and historical rules of the firewall (that is not deleted),
255+
using version. Whenever the rules update, the version increments from 1.
256+
:rtype: dict
257+
"""
258+
return self._client.get(
259+
"{}/history".format(self.api_endpoint), model=self
260+
)
261+
262+
def get_rule_version(self, version):
263+
"""
264+
Gets the JSON for a specific rule version for this Firewall.
265+
266+
API Documentation: https://techdocs.akamai.com/linode-api/reference/get-firewall-rule-version
267+
268+
:param version: The firewall rule version to view.
269+
:type version: int
270+
271+
:returns: Gets a specific firewall rule version for an enabled or disabled firewall.
272+
:rtype: dict
273+
"""
274+
return self._client.get(
275+
"{}/history/rules/{}".format(self.api_endpoint, version), model=self
276+
)
277+
247278
def device_create(self, id, type="linode", **kwargs):
248279
"""
249280
Creates and attaches a device to this Firewall

0 commit comments

Comments
 (0)