Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions linode_api4/groups/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from .linode import *
from .lke import *
from .lke_tier import *
from .lock import *
from .longview import *
from .maintenance import *
from .monitor import *
Expand Down
56 changes: 56 additions & 0 deletions linode_api4/groups/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
ChildAccount,
Event,
Invoice,
Lock,
Login,
MappedObject,
OAuthClient,
Expand Down Expand Up @@ -510,3 +511,58 @@ def child_accounts(self, *filters):
:rtype: PaginatedList of ChildAccount
"""
return self.client._get_and_filter(ChildAccount, *filters)

def locks(self, *filters):
"""
Returns a list of all resource locks on the account.

API Documentation: https://techdocs.akamai.com/linode-api/reference/get-locks

: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 resource locks on the account.
:rtype: PaginatedList of Lock
"""
return self.client._get_and_filter(Lock, *filters)

def lock_create(self, entity_type, entity_id, lock_type, **kwargs):
"""
Creates a resource lock to prevent deletion or modification.

API Documentation: https://techdocs.akamai.com/linode-api/reference/post-lock

:param entity_type: The type of entity to lock (e.g., "linode").
:type entity_type: str
:param entity_id: The ID of the entity to lock.
:type entity_id: int
:param lock_type: The type of lock (e.g., "cannot_delete").
:type lock_type: str or LockType

:returns: The created resource lock.
:rtype: Lock
"""
from linode_api4.objects.lock import ( # pylint: disable=import-outside-toplevel
LockType,
)

params = {
"entity_type": entity_type,
"entity_id": entity_id,
"lock_type": (
lock_type.value
if isinstance(lock_type, LockType)
else lock_type
),
}
params.update(kwargs)

result = self.client.post("/locks", data=params)

if "id" not in result:
raise UnexpectedResponseError(
"Unexpected response when creating lock!", json=result
)

return Lock(self.client, result["id"], result)
89 changes: 89 additions & 0 deletions linode_api4/groups/lock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
from typing import Union

from linode_api4.errors import UnexpectedResponseError
from linode_api4.groups import Group
from linode_api4.objects import Lock, LockType

__all__ = ["LockGroup"]


class LockGroup(Group):
"""
Encapsulates methods for interacting with Resource Locks.

Resource locks prevent deletion or modification of resources.
Currently, only Linode instances can be locked.
"""

def __call__(self, *filters):
"""
Returns a list of all Resource Locks on the account.

This is intended to be called off of the :any:`LinodeClient`
class, like this::

locks = client.locks()

API Documentation: https://techdocs.akamai.com/linode-api/reference/get-locks

: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 Resource Locks on the account.
:rtype: PaginatedList of Lock
"""
return self.client._get_and_filter(Lock, *filters)

def create(
self,
entity_type: str,
entity_id: Union[int, str],
lock_type: Union[LockType, str] = LockType.cannot_delete,
) -> Lock:
"""
Creates a new Resource Lock for the specified entity.

API Documentation: https://techdocs.akamai.com/linode-api/reference/post-lock

:param entity_type: The type of entity to lock (e.g., "linode").
:type entity_type: str
:param entity_id: The ID of the entity to lock.
:type entity_id: int or str
:param lock_type: The type of lock to create. Defaults to "cannot_delete".
:type lock_type: LockType or str

:returns: The newly created Resource Lock.
:rtype: Lock
"""
params = {
"entity_type": entity_type,
"entity_id": entity_id,
"lock_type": lock_type,
}

result = self.client.post("/locks", data=params)

if "id" not in result:
raise UnexpectedResponseError(
"Unexpected response when creating lock!", json=result
)

return Lock(self.client, result["id"], result)

def delete(self, lock: Union[Lock, int]) -> bool:
"""
Deletes a Resource Lock.

API Documentation: https://techdocs.akamai.com/linode-api/reference/delete-lock

:param lock: The Lock to delete, or its ID.
:type lock: Lock or int

:returns: True if the lock was successfully deleted.
:rtype: bool
"""
lock_id = lock.id if isinstance(lock, Lock) else lock

self.client.delete(f"/locks/{lock_id}")
return True
4 changes: 4 additions & 0 deletions linode_api4/linode_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
ImageGroup,
LinodeGroup,
LKEGroup,
LockGroup,
LongviewGroup,
MaintenanceGroup,
MetricsGroup,
Expand Down Expand Up @@ -454,6 +455,9 @@ def __init__(

self.monitor = MonitorGroup(self)

#: Access methods related to Resource Locks - See :any:`LockGroup` for more information.
self.locks = LockGroup(self)

super().__init__(
token=token,
base_url=base_url,
Expand Down
1 change: 1 addition & 0 deletions linode_api4/objects/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@
from .placement import *
from .monitor import *
from .monitor_api import *
from .lock import *
1 change: 1 addition & 0 deletions linode_api4/objects/linode.py
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,7 @@ class Instance(Base):
"maintenance_policy": Property(
mutable=True
), # Note: This field is only available when using v4beta.
"locks": Property(unordered=True),
}

@property
Expand Down
47 changes: 47 additions & 0 deletions linode_api4/objects/lock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from dataclasses import dataclass

from linode_api4.objects.base import Base, Property
from linode_api4.objects.serializable import JSONObject, StrEnum

__all__ = ["LockType", "LockEntity", "Lock"]


class LockType(StrEnum):
"""
LockType defines valid values for resource lock types.

API Documentation: https://techdocs.akamai.com/linode-api/reference/post-lock
"""

cannot_delete = "cannot_delete"
cannot_delete_with_subresources = "cannot_delete_with_subresources"


@dataclass
class LockEntity(JSONObject):
"""
Represents the entity that is locked.

API Documentation: https://techdocs.akamai.com/linode-api/reference/get-lock
"""

id: int = 0
type: str = ""
label: str = ""
url: str = ""


class Lock(Base):
"""
A resource lock that prevents deletion or modification of a resource.

API Documentation: https://techdocs.akamai.com/linode-api/reference/get-lock
"""

api_endpoint = "/locks/{id}"

properties = {
"id": Property(identifier=True),
"lock_type": Property(),
"entity": Property(json_object=LockEntity),
}
27 changes: 27 additions & 0 deletions test/fixtures/locks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"data": [
{
"id": 1,
"lock_type": "cannot_delete",
"entity": {
"id": 123,
"type": "linode",
"label": "test-linode",
"url": "/v4/linode/instances/123"
}
},
{
"id": 2,
"lock_type": "cannot_delete_with_subresources",
"entity": {
"id": 456,
"type": "linode",
"label": "another-linode",
"url": "/v4/linode/instances/456"
}
}
],
"page": 1,
"pages": 1,
"results": 2
}
10 changes: 10 additions & 0 deletions test/fixtures/locks_1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"id": 1,
"lock_type": "cannot_delete",
"entity": {
"id": 123,
"type": "linode",
"label": "test-linode",
"url": "/v4/linode/instances/123"
}
}
1 change: 1 addition & 0 deletions test/integration/models/lock/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# This file is intentionally left empty to make the directory a Python package.
Loading
Loading