Skip to content

Commit 31c34c5

Browse files
committed
Merge branch 'dev' into feature/TPT-4207-sdks-add-integration-tests-for-nodebalancer-front-end-ip-in-vpc
2 parents 5a9348d + d18b54e commit 31c34c5

15 files changed

Lines changed: 223 additions & 280 deletions

docs/conf.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@
1010

1111
# If extensions (or modules to document with autodoc) are in another directory,
1212
# add these directories to sys.path here. If the directory is relative to the
13-
# documentation root, use os.path.abspath to make it absolute, like shown here.
13+
# documentation root, use Path(...).absolute() to make it absolute, like shown here.
1414
#
15-
import os
1615
import sys
17-
sys.path.insert(0, os.path.abspath('..'))
16+
from pathlib import Path
17+
sys.path.insert(0, str(Path('..').absolute()))
1818

1919

2020
# -- Project information -----------------------------------------------------

linode_api4/common.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import os
21
from dataclasses import dataclass
2+
from pathlib import Path
33

44
from linode_api4.objects import JSONObject
55

@@ -47,9 +47,9 @@ def load_and_validate_keys(authorized_keys):
4747
ret.append(k)
4848
else:
4949
# it doesn't appear to be a key.. is it a path to the key?
50-
k = os.path.expanduser(k)
51-
if os.path.isfile(k):
52-
with open(k) as f:
50+
k_path = Path(k).expanduser()
51+
if k_path.is_file():
52+
with open(k_path) as f:
5353
ret.append(f.read().rstrip())
5454
else:
5555
raise ValueError(

linode_api4/groups/linode.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import base64
2-
import os
2+
from pathlib import Path
33
from typing import Any, Dict, List, Optional, Union
44

55
from linode_api4.common import load_and_validate_keys
@@ -457,8 +457,9 @@ def stackscript_create(
457457
script_body = script
458458
if not script.startswith("#!"):
459459
# it doesn't look like a stackscript body, let's see if it's a file
460-
if os.path.isfile(script):
461-
with open(script) as f:
460+
script_path = Path(script)
461+
if script_path.is_file():
462+
with open(script_path) as f:
462463
script_body = f.read()
463464
else:
464465
raise ValueError(

linode_api4/groups/profile.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import os
21
from datetime import datetime
2+
from pathlib import Path
33

44
from linode_api4 import UnexpectedResponseError
55
from linode_api4.common import SSH_KEY_TYPES
@@ -322,9 +322,9 @@ def ssh_key_upload(self, key, label):
322322
"""
323323
if not key.startswith(SSH_KEY_TYPES):
324324
# this might be a file path - look for it
325-
path = os.path.expanduser(key)
326-
if os.path.isfile(path):
327-
with open(path) as f:
325+
key_path = Path(key).expanduser()
326+
if key_path.is_file():
327+
with open(key_path) as f:
328328
key = f.read().strip()
329329
if not key.startswith(SSH_KEY_TYPES):
330330
raise ValueError("Invalid SSH Public Key")

linode_api4/objects/database.py

Lines changed: 0 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
from dataclasses import dataclass, field
22
from typing import Optional
33

4-
from deprecated import deprecated
5-
64
from linode_api4.objects import (
75
Base,
8-
DerivedBase,
96
JSONObject,
107
MappedObject,
118
Property,
@@ -86,69 +83,6 @@ class DatabasePrivateNetwork(JSONObject):
8683
public_access: Optional[bool] = None
8784

8885

89-
@deprecated(
90-
reason="Backups are not supported for non-legacy database clusters."
91-
)
92-
class DatabaseBackup(DerivedBase):
93-
"""
94-
A generic Managed Database backup.
95-
96-
This class is not intended to be used on its own.
97-
Use the appropriate subclasses for the corresponding database engine. (e.g. MySQLDatabaseBackup)
98-
"""
99-
100-
api_endpoint = ""
101-
derived_url_path = "backups"
102-
parent_id_name = "database_id"
103-
104-
properties = {
105-
"created": Property(is_datetime=True),
106-
"id": Property(identifier=True),
107-
"label": Property(),
108-
"type": Property(),
109-
}
110-
111-
def restore(self):
112-
"""
113-
Restore a backup to a Managed Database on your Account.
114-
115-
API Documentation:
116-
117-
- MySQL: https://techdocs.akamai.com/linode-api/reference/post-databases-mysql-instance-backup-restore
118-
- PostgreSQL: https://techdocs.akamai.com/linode-api/reference/post-databases-postgre-sql-instance-backup-restore
119-
"""
120-
121-
return self._client.post(
122-
"{}/restore".format(self.api_endpoint), model=self
123-
)
124-
125-
126-
@deprecated(
127-
reason="Backups are not supported for non-legacy database clusters."
128-
)
129-
class MySQLDatabaseBackup(DatabaseBackup):
130-
"""
131-
A backup for an accessible Managed MySQL Database.
132-
133-
API Documentation: https://techdocs.akamai.com/linode-api/reference/get-databases-mysql-instance-backup
134-
"""
135-
136-
api_endpoint = "/databases/mysql/instances/{database_id}/backups/{id}"
137-
138-
139-
@deprecated(
140-
reason="Backups are not supported for non-legacy database clusters."
141-
)
142-
class PostgreSQLDatabaseBackup(DatabaseBackup):
143-
"""
144-
A backup for an accessible Managed PostgreSQL Database.
145-
146-
API Documentation: https://techdocs.akamai.com/linode-api/reference/get-databases-postgresql-instance-backup
147-
"""
148-
149-
api_endpoint = "/databases/postgresql/instances/{database_id}/backups/{id}"
150-
151-
15286
@dataclass
15387
class MySQLDatabaseConfigMySQLOptions(JSONObject):
15488
"""
@@ -296,15 +230,13 @@ class MySQLDatabase(Base):
296230
"id": Property(identifier=True),
297231
"label": Property(mutable=True),
298232
"allow_list": Property(mutable=True, unordered=True),
299-
"backups": Property(derived_class=MySQLDatabaseBackup),
300233
"cluster_size": Property(mutable=True),
301234
"created": Property(is_datetime=True),
302235
"encrypted": Property(),
303236
"engine": Property(),
304237
"hosts": Property(),
305238
"port": Property(),
306239
"region": Property(),
307-
"replication_type": Property(),
308240
"ssl_connection": Property(),
309241
"status": Property(volatile=True),
310242
"type": Property(mutable=True),
@@ -393,28 +325,6 @@ def patch(self):
393325
"{}/patch".format(MySQLDatabase.api_endpoint), model=self
394326
)
395327

396-
@deprecated(
397-
reason="Backups are not supported for non-legacy database clusters."
398-
)
399-
def backup_create(self, label, **kwargs):
400-
"""
401-
Creates a snapshot backup of a Managed MySQL Database.
402-
403-
API Documentation: https://techdocs.akamai.com/linode-api/reference/post-databases-mysql-instance-backup
404-
"""
405-
406-
params = {
407-
"label": label,
408-
}
409-
params.update(kwargs)
410-
411-
self._client.post(
412-
"{}/backups".format(MySQLDatabase.api_endpoint),
413-
model=self,
414-
data=params,
415-
)
416-
self.invalidate()
417-
418328
def invalidate(self):
419329
"""
420330
Clear out cached properties.
@@ -464,16 +374,13 @@ class PostgreSQLDatabase(Base):
464374
"id": Property(identifier=True),
465375
"label": Property(mutable=True),
466376
"allow_list": Property(mutable=True, unordered=True),
467-
"backups": Property(derived_class=PostgreSQLDatabaseBackup),
468377
"cluster_size": Property(mutable=True),
469378
"created": Property(is_datetime=True),
470379
"encrypted": Property(),
471380
"engine": Property(),
472381
"hosts": Property(),
473382
"port": Property(),
474383
"region": Property(),
475-
"replication_commit_type": Property(),
476-
"replication_type": Property(),
477384
"ssl_connection": Property(),
478385
"status": Property(volatile=True),
479386
"type": Property(mutable=True),
@@ -563,28 +470,6 @@ def patch(self):
563470
"{}/patch".format(PostgreSQLDatabase.api_endpoint), model=self
564471
)
565472

566-
@deprecated(
567-
reason="Backups are not supported for non-legacy database clusters."
568-
)
569-
def backup_create(self, label, **kwargs):
570-
"""
571-
Creates a snapshot backup of a Managed PostgreSQL Database.
572-
573-
API Documentation: https://techdocs.akamai.com/linode-api/reference/post-databases-postgre-sql-instance-backup
574-
"""
575-
576-
params = {
577-
"label": label,
578-
}
579-
params.update(kwargs)
580-
581-
self._client.post(
582-
"{}/backups".format(PostgreSQLDatabase.api_endpoint),
583-
model=self,
584-
data=params,
585-
)
586-
self.invalidate()
587-
588473
def invalidate(self):
589474
"""
590475
Clear out cached properties.

linode_api4/objects/linode.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,12 @@
4040
from linode_api4.objects.serializable import JSONObject, StrEnum
4141
from linode_api4.objects.vpc import VPC, VPCSubnet
4242
from linode_api4.paginated_list import PaginatedList
43-
from linode_api4.util import drop_null_keys
43+
from linode_api4.util import drop_null_keys, generate_device_suffixes
4444

4545
PASSWORD_CHARS = string.ascii_letters + string.digits + string.punctuation
46+
MIN_DEVICE_LIMIT = 8
47+
MB_PER_GB = 1024
48+
MAX_DEVICE_LIMIT = 64
4649

4750

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

12741277
hypervisor_prefix = "sd" if self.hypervisor == "kvm" else "xvd"
1278+
1279+
device_limit = int(
1280+
max(
1281+
MIN_DEVICE_LIMIT,
1282+
min(self.specs.memory // MB_PER_GB, MAX_DEVICE_LIMIT),
1283+
)
1284+
)
1285+
12751286
device_names = [
1276-
hypervisor_prefix + string.ascii_lowercase[i] for i in range(0, 8)
1287+
hypervisor_prefix + suffix
1288+
for suffix in generate_device_suffixes(device_limit)
12771289
]
1290+
12781291
device_map = {
12791292
device_names[i]: None for i in range(0, len(device_names))
12801293
}

linode_api4/objects/nodebalancer.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import os
1+
from pathlib import Path
22
from urllib import parse
33

44
from linode_api4.common import Price, RegionPrice
@@ -220,12 +220,14 @@ def load_ssl_data(self, cert_file, key_file):
220220

221221
# we're disabling warnings here because these attributes are defined dynamically
222222
# through linode.objects.Base, and pylint isn't privy
223-
if os.path.isfile(os.path.expanduser(cert_file)):
224-
with open(os.path.expanduser(cert_file)) as f:
223+
cert_path = Path(cert_file).expanduser()
224+
if cert_path.is_file():
225+
with open(cert_path) as f:
225226
self.ssl_cert = f.read()
226227

227-
if os.path.isfile(os.path.expanduser(key_file)):
228-
with open(os.path.expanduser(key_file)) as f:
228+
key_path = Path(key_file).expanduser()
229+
if key_path.is_file():
230+
with open(key_path) as f:
229231
self.ssl_key = f.read()
230232

231233

linode_api4/util.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Contains various utility functions.
33
"""
44

5+
import string
56
from typing import Any, Dict
67

78

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

2930
return recursive_helper(data)
31+
32+
33+
def generate_device_suffixes(n: int) -> list[str]:
34+
"""
35+
Generate n alphabetical suffixes starting with a, b, c, etc.
36+
After z, continue with aa, ab, ac, etc. followed by aaa, aab, etc.
37+
Example:
38+
generate_device_suffixes(30) ->
39+
['a', 'b', 'c', ..., 'z', 'aa', 'ab', 'ac', 'ad']
40+
"""
41+
letters = string.ascii_lowercase
42+
result = []
43+
i = 0
44+
45+
while len(result) < n:
46+
s = ""
47+
x = i
48+
while True:
49+
s = letters[x % 26] + s
50+
x = x // 26 - 1
51+
if x < 0:
52+
break
53+
result.append(s)
54+
i += 1
55+
return result

test/fixtures/databases_mysql_instances_123_backups.json

Lines changed: 0 additions & 13 deletions
This file was deleted.

test/fixtures/databases_mysql_instances_123_backups_456_restore.json

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)