Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
17 changes: 15 additions & 2 deletions 17 linode_api4/objects/linode.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,12 @@
from linode_api4.objects.serializable import JSONObject, StrEnum
from linode_api4.objects.vpc import VPC, VPCSubnet
from linode_api4.paginated_list import PaginatedList
from linode_api4.util import drop_null_keys
from linode_api4.util import drop_null_keys, generate_device_suffixes

PASSWORD_CHARS = string.ascii_letters + string.digits + string.punctuation
MIN_DEVICE_LIMIT = 8
MB_PER_GB = 1024
MAX_DEVICE_LIMIT = 64


class InstanceDiskEncryptionType(StrEnum):
Expand Down Expand Up @@ -1272,9 +1275,19 @@ def config_create(
from .volume import Volume # pylint: disable=import-outside-toplevel

hypervisor_prefix = "sd" if self.hypervisor == "kvm" else "xvd"

device_limit = int(
max(
MIN_DEVICE_LIMIT,
min(self.specs.memory // MB_PER_GB, MAX_DEVICE_LIMIT),
)
)

device_names = [
hypervisor_prefix + string.ascii_lowercase[i] for i in range(0, 8)
hypervisor_prefix + suffix
for suffix in generate_device_suffixes(device_limit)
]

device_map = {
device_names[i]: None for i in range(0, len(device_names))
}
Expand Down
26 changes: 26 additions & 0 deletions 26 linode_api4/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Contains various utility functions.
"""

import string
from typing import Any, Dict


Expand All @@ -27,3 +28,28 @@ def recursive_helper(value: Any) -> Any:
return value

return recursive_helper(data)


def generate_device_suffixes(n: int) -> list[str]:
"""
Generate n alphabetical suffixes starting with a, b, c, etc.
After z, continue with aa, ab, ac, etc. followed by aaa, aab, etc.
Example:
generate_device_suffixes(30) ->
['a', 'b', 'c', ..., 'z', 'aa', 'ab', 'ac', 'ad']
"""
letters = string.ascii_lowercase
result = []
i = 0

while len(result) < n:
s = ""
x = i
while True:
s = letters[x % 26] + s
x = x // 26 - 1
if x < 0:
break
result.append(s)
i += 1
return result
40 changes: 40 additions & 0 deletions 40 test/integration/models/volume/test_blockstorage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from test.integration.conftest import get_region
from test.integration.helpers import get_test_label, retry_sending_request


def test_config_create_with_extended_volume_limit(test_linode_client):
client = test_linode_client

region = get_region(client, {"Linodes", "Block Storage"}, site_type="core")
label = get_test_label()

linode, _ = client.linode.instance_create(
"g6-standard-6",
region,
image="linode/debian12",
label=label,
)

volumes = [
client.volume_create(
f"{label}-vol-{i}",
region=region,
size=10,
)
for i in range(12)
]

config = linode.config_create(volumes=volumes)

devices = config._raw_json["devices"]

assert len([d for d in devices.values() if d is not None]) == 12

assert "sdi" in devices
assert "sdj" in devices
assert "sdk" in devices
assert "sdl" in devices

linode.delete()
for v in volumes:
retry_sending_request(3, v.delete)
121 changes: 120 additions & 1 deletion 121 test/unit/util_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import unittest

from linode_api4.util import drop_null_keys
from linode_api4.util import drop_null_keys, generate_device_suffixes


class UtilTest(unittest.TestCase):
Expand Down Expand Up @@ -53,3 +53,122 @@ def test_drop_null_keys_recursive(self):
}

assert drop_null_keys(value) == expected_output

def test_generate_device_suffixes(self):
"""
Tests whether generate_device_suffixes works as expected.
"""

expected_output_12 = [
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
]
assert generate_device_suffixes(12) == expected_output_12

expected_output_30 = [
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z",
"aa",
"ab",
"ac",
"ad",
]
assert generate_device_suffixes(30) == expected_output_30

expected_output_60 = [
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z",
"aa",
"ab",
"ac",
"ad",
"ae",
"af",
"ag",
"ah",
"ai",
"aj",
"ak",
"al",
"am",
"an",
"ao",
"ap",
"aq",
"ar",
"as",
"at",
"au",
"av",
"aw",
"ax",
"ay",
"az",
"ba",
"bb",
"bc",
"bd",
"be",
"bf",
"bg",
"bh",
]
assert generate_device_suffixes(60) == expected_output_60
Morty Proxy This is a proxified and sanitized view of the page, visit original site.