Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/clean-release-notes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:

steps:
- name: Remove ticket prefixes from release notes
uses: actions/github-script@v8
uses: actions/github-script@v9
with:
script: |
const release = context.payload.release;
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dependency-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ jobs:
- name: 'Checkout repository'
uses: actions/checkout@v6
- name: 'Dependency Review'
uses: actions/dependency-review-action@v4
uses: actions/dependency-review-action@v5
with:
comment-summary-in-pr: on-failure
2 changes: 1 addition & 1 deletion .github/workflows/e2e-test-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ jobs:
LINODE_CLI_OBJ_ACCESS_KEY: ${{ secrets.LINODE_CLI_OBJ_ACCESS_KEY }}
LINODE_CLI_OBJ_SECRET_KEY: ${{ secrets.LINODE_CLI_OBJ_SECRET_KEY }}

- uses: actions/github-script@v8
- uses: actions/github-script@v9
id: update-check-run
if: ${{ inputs.pull_request_number != '' && fromJson(steps.commit-hash.outputs.data).repository.pullRequest.headRef.target.oid == inputs.sha }}
env:
Expand Down
83 changes: 55 additions & 28 deletions linode_api4/groups/linode.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ def instance_create(
interface_generation: Optional[Union[InterfaceGeneration, str]] = None,
network_helper: Optional[bool] = None,
maintenance_policy: Optional[str] = None,
root_pass: Optional[str] = None,
kernel: Optional[str] = None,
boot_size: Optional[int] = None,
authorized_users: Optional[List[str]] = None,
**kwargs,
):
"""
Expand All @@ -172,27 +176,26 @@ def instance_create(
To create an Instance from an :any:`Image`, call `instance_create` with
a :any:`Type`, a :any:`Region`, and an :any:`Image`. All three of
these fields may be provided as either the ID or the appropriate object.
In this mode, a root password will be generated and returned with the
new Instance object.
When an Image is provided, at least one of ``root_pass``, ``authorized_users``, or
``authorized_keys`` must also be given.

For example::

new_linode, password = client.linode.instance_create(
new_linode = client.linode.instance_create(
"g6-standard-2",
"us-east",
image="linode/debian9")
image="linode/debian13",
root_pass="aComplex@Password123")

ltype = client.linode.types().first()
region = client.regions().first()
image = client.images().first()

another_linode, password = client.linode.instance_create(
another_linode = client.linode.instance_create(
ltype,
region,
image=image)

To output the password from the above example:
print(password)
image=image,
authorized_keys="ssh-rsa AAAA")

To output the first IPv4 address of the new Linode:
print(new_linode.ipv4[0])
Expand All @@ -210,10 +213,11 @@ def instance_create(

stackscript = StackScript(client, 10079)

new_linode, password = client.linode.instance_create(
new_linode = client.linode.instance_create(
"g6-standard-2",
"us-east",
image="linode/debian9",
image="linode/debian13",
root_pass="aComplex@Password123",
stackscript=stackscript,
stackscript_data={"gh_username": "example"})

Expand Down Expand Up @@ -244,10 +248,11 @@ def instance_create(
To create a new Instance with explicit interfaces, provide list of
LinodeInterfaceOptions objects or dicts to the "interfaces" field::

linode, password = client.linode.instance_create(
linode = client.linode.instance_create(
"g6-standard-1",
"us-mia",
image="linode/ubuntu24.04",
root_pass="aComplex@Password123",

# This can be configured as an account-wide default
interface_generation=InterfaceGeneration.LINODE,
Expand Down Expand Up @@ -280,10 +285,14 @@ def instance_create(
:type ltype: str or Type
:param region: The Region in which we are creating the Instance
:type region: str or Region
:param image: The Image to deploy to this Instance. If this is provided
and no root_pass is given, a password will be generated
and returned along with the new Instance.
:param image: The Image to deploy to this Instance. If this is provided,
at least one of root_pass, authorized_users, or authorized_keys must also be
provided.
:type image: str or Image
:param root_pass: The root password for the new Instance. Required when
an image is provided and neither authorized_users nor
authorized_keys are given.
:type root_pass: str
:param stackscript: The StackScript to deploy to the new Instance. If
provided, "image" is required and must be compatible
with the chosen StackScript.
Expand All @@ -300,6 +309,11 @@ def instance_create(
be a single key, or a path to a file containing
the key.
:type authorized_keys: list or str
:param authorized_users: A list of usernames whose keys should be installed
as trusted for the root user. These user's keys
should already be set up, see :any:`ProfileGroup.ssh_keys`
for details.
:type authorized_users: list[str]
:param label: The display label for the new Instance
:type label: str
:param group: The display group for the new Instance
Expand Down Expand Up @@ -335,26 +349,39 @@ def instance_create(
:param maintenance_policy: The slug of the maintenance policy to apply during maintenance.
If not provided, the default policy (linode/migrate) will be applied.
:type maintenance_policy: str

:returns: A new Instance object, or a tuple containing the new Instance and
the generated password.
:rtype: Instance or tuple(Instance, str)
:param kernel: The kernel to boot the Instance with. If provided, this will be used as the
kernel for the default configuration profile.
:type kernel: str
:param boot_size: The size of the boot disk in MB. If provided, this will be used to create
the boot disk for the Instance.
:type boot_size: int

:returns: A new Instance object
:rtype: Instance
:raises ApiError: If contacting the API fails
:raises UnexpectedResponseError: If the API response is somehow malformed.
This usually indicates that you are using
an outdated library.
"""

ret_pass = None
if image and not "root_pass" in kwargs:
ret_pass = Instance.generate_root_password()
kwargs["root_pass"] = ret_pass
if (
image
and not root_pass
and not authorized_keys
and not authorized_users
):
raise ValueError(
"When creating an Instance from an Image, at least one of "
"root_pass, authorized_users, or authorized_keys must be provided."
)

params = {
"type": ltype,
"region": region,
"image": image,
"root_pass": root_pass,
"authorized_keys": load_and_validate_keys(authorized_keys),
"authorized_users": authorized_users,
# These will automatically be flattened below
"firewall_id": firewall,
"backup_id": backup,
Expand All @@ -372,6 +399,8 @@ def instance_create(
"interfaces": interfaces,
"interface_generation": interface_generation,
"network_helper": network_helper,
"kernel": kernel,
"boot_size": boot_size,
}

params.update(kwargs)
Expand All @@ -386,10 +415,7 @@ def instance_create(
"Unexpected response when creating linode!", json=result
)

l = Instance(self.client, result["id"], result)
if not ret_pass:
return l
return l, ret_pass
return Instance(self.client, result["id"], result)

@staticmethod
def build_instance_metadata(user_data=None, encode_user_data=True):
Expand All @@ -398,10 +424,11 @@ def build_instance_metadata(user_data=None, encode_user_data=True):
the :any:`instance_create` method. This helper can also be used
when cloning and rebuilding Instances.
**Creating an Instance with User Data**::
new_linode, password = client.linode.instance_create(
new_linode = client.linode.instance_create(
"g6-standard-2",
"us-east",
image="linode/ubuntu22.04",
root_pass="aComplex@Password123",
metadata=client.linode.build_instance_metadata(user_data="myuserdata")
)
:param user_data: User-defined data to provide to the Linode Instance through
Expand Down
4 changes: 2 additions & 2 deletions linode_api4/groups/lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def __call__(self, *filters):
locks = client.locks()
API Documentation: TBD
API Documentation: https://techdocs.akamai.com/linode-api/reference/get-resource-locks
:param filters: Any number of filters to apply to this query.
See :doc:`Filtering Collections</linode_api4/objects/filtering>`
Expand All @@ -44,7 +44,7 @@ def create(
"""
Creates a new Resource Lock for the specified entity.
API Documentation: TBD
API Documentation: https://techdocs.akamai.com/linode-api/reference/post-resource-lock
:param entity_type: The type of entity to lock (e.g., "linode").
:type entity_type: str
Expand Down
4 changes: 2 additions & 2 deletions linode_api4/groups/networking.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,10 +452,10 @@ def ip_addresses_assign(self, assignments, region):
:param assignments: Any number of assignments to make. See
:any:`IPAddress.to` for details on how to construct
assignments.
:type assignments: dct
:type assignments: list
"""

for a in assignments["assignments"]:
for a in assignments:
if not "address" in a or not "linode_id" in a:
raise ValueError("Invalid assignment: {}".format(a))

Expand Down
16 changes: 16 additions & 0 deletions linode_api4/groups/object_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
ObjectStorageACL,
ObjectStorageBucket,
ObjectStorageCluster,
ObjectStorageGlobalQuota,
ObjectStorageKeyPermission,
ObjectStorageKeys,
ObjectStorageQuota,
Expand Down Expand Up @@ -533,3 +534,18 @@ def quotas(self, *filters):
:rtype: PaginatedList of ObjectStorageQuota
"""
return self.client._get_and_filter(ObjectStorageQuota, *filters)

def global_quotas(self, *filters):
"""
Lists the active account-level Object Storage quotas applied to your account.

API Documentation: TBD

: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 account-level Object Storage Quotas that matched the query.
:rtype: PaginatedList of ObjectStorageGlobalQuota
"""
return self.client._get_and_filter(ObjectStorageGlobalQuota, *filters)
7 changes: 1 addition & 6 deletions linode_api4/objects/database.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
from dataclasses import dataclass, field
from typing import Optional

from linode_api4.objects import (
Base,
JSONObject,
MappedObject,
Property,
)
from linode_api4.objects import Base, JSONObject, MappedObject, Property


class DatabaseType(Base):
Expand Down
Loading
Loading