Skip to content

Commit 1566086

Browse files
[MISC] Port MySQL operator to Python 3.10+ (#661)
1 parent a64910d commit 1566086

File tree

10 files changed

+67
-78
lines changed

10 files changed

+67
-78
lines changed

src/charm.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import socket
1616
import subprocess
1717
from time import sleep
18-
from typing import Optional
1918

2019
import ops
2120
from charms.data_platform_libs.v0.data_models import TypedCharmBase
@@ -400,7 +399,7 @@ def _on_database_storage_detaching(self, _) -> None:
400399
if not self._mysql.is_instance_in_cluster(self.unit_label):
401400
return
402401

403-
def _get_leader_unit() -> Optional[Unit]:
402+
def _get_leader_unit() -> Unit | None:
404403
"""Get the leader unit."""
405404
for unit in self.peers.units:
406405
if self.peers.data[unit]["leader"] == "true":
@@ -630,7 +629,7 @@ def _on_cos_agent_relation_broken(self, _: RelationBrokenEvent) -> None:
630629
# =======================
631630

632631
@property
633-
def tracing_endpoint(self) -> Optional[str]:
632+
def tracing_endpoint(self) -> str | None:
634633
"""Otlp http endpoint for charm instrumentation."""
635634
return self.tracing_endpoint_config
636635

@@ -665,15 +664,15 @@ def unit_fqdn(self) -> str:
665664
return socket.getfqdn()
666665

667666
@property
668-
def restart_peers(self) -> Optional[ops.Relation]:
667+
def restart_peers(self) -> ops.Relation | None:
669668
"""Retrieve the peer relation."""
670669
return self.model.get_relation("restart")
671670

672671
def is_unit_busy(self) -> bool:
673672
"""Returns whether the unit is in blocked state and should not run any operations."""
674673
return self.unit_peer_data.get("member-state") == "waiting"
675674

676-
def get_unit_hostname(self, unit_name: Optional[str] = None) -> str:
675+
def get_unit_hostname(self, unit_name: str | None = None) -> str:
677676
"""Get the hostname of the unit."""
678677
if unit_name:
679678
unit = self.model.get_unit(unit_name)
@@ -876,7 +875,7 @@ def _is_unit_waiting_to_join_cluster(self) -> bool:
876875
and self.cluster_initialized
877876
)
878877

879-
def _get_primary_from_online_peer(self) -> Optional[str]:
878+
def _get_primary_from_online_peer(self) -> str | None:
880879
"""Get the primary address from an online peer."""
881880
for unit in self.peers.units:
882881
if self.peers.data[unit].get("member-state") == "online":

src/config.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import logging
99
import os
1010
import re
11-
from typing import Optional
1211

1312
from charms.data_platform_libs.v0.data_models import BaseConfigModel
1413
from charms.mysql.v0.mysql import MAX_CONNECTIONS_FLOOR
@@ -44,7 +43,7 @@ def filter_static_keys(self, keys: set) -> set:
4443
return keys - self.static_config
4544

4645
@property
47-
def custom_config(self) -> Optional[dict]:
46+
def custom_config(self) -> dict | None:
4847
"""Return current custom config dict."""
4948
if not os.path.exists(self.config_file_path):
5049
return None
@@ -61,12 +60,12 @@ class CharmConfig(BaseConfigModel):
6160
"""Manager for the structured configuration."""
6261

6362
profile: str
64-
cluster_name: Optional[str]
65-
cluster_set_name: Optional[str]
66-
profile_limit_memory: Optional[int]
67-
mysql_interface_user: Optional[str]
68-
mysql_interface_database: Optional[str]
69-
experimental_max_connections: Optional[int]
63+
cluster_name: str | None
64+
cluster_set_name: str | None
65+
profile_limit_memory: int | None
66+
mysql_interface_user: str | None
67+
mysql_interface_database: str | None
68+
experimental_max_connections: int | None
7069
binlog_retention_days: int
7170
plugin_audit_enabled: bool
7271
plugin_audit_strategy: str
@@ -75,7 +74,7 @@ class CharmConfig(BaseConfigModel):
7574

7675
@validator("profile")
7776
@classmethod
78-
def profile_values(cls, value: str) -> Optional[str]:
77+
def profile_values(cls, value: str) -> str | None:
7978
"""Check profile config option is one of `testing` or `production`."""
8079
if value not in ["testing", "production"]:
8180
raise ValueError("Value not one of 'testing' or 'production'")
@@ -84,7 +83,7 @@ def profile_values(cls, value: str) -> Optional[str]:
8483

8584
@validator("cluster_name", "cluster_set_name")
8685
@classmethod
87-
def cluster_name_validator(cls, value: str) -> Optional[str]:
86+
def cluster_name_validator(cls, value: str) -> str | None:
8887
"""Check for valid cluster, cluster-set name.
8988
9089
Limited to 63 characters, and must start with a letter and
@@ -106,7 +105,7 @@ def cluster_name_validator(cls, value: str) -> Optional[str]:
106105

107106
@validator("profile_limit_memory")
108107
@classmethod
109-
def profile_limit_memory_validator(cls, value: int) -> Optional[int]:
108+
def profile_limit_memory_validator(cls, value: int) -> int | None:
110109
"""Check profile limit memory."""
111110
if value < 600:
112111
raise ValueError("MySQL Charm requires at least 600MB for bootstrapping")
@@ -117,7 +116,7 @@ def profile_limit_memory_validator(cls, value: int) -> Optional[int]:
117116

118117
@validator("experimental_max_connections")
119118
@classmethod
120-
def experimental_max_connections_validator(cls, value: int) -> Optional[int]:
119+
def experimental_max_connections_validator(cls, value: int) -> int | None:
121120
"""Check experimental max connections."""
122121
if value < MAX_CONNECTIONS_FLOOR:
123122
raise ValueError(
@@ -138,7 +137,7 @@ def binlog_retention_days_validator(cls, value: int) -> int:
138137

139138
@validator("plugin_audit_strategy")
140139
@classmethod
141-
def plugin_audit_strategy_validator(cls, value: str) -> Optional[str]:
140+
def plugin_audit_strategy_validator(cls, value: str) -> str | None:
142141
"""Check profile config option is one of `testing` or `production`."""
143142
if value not in ["async", "semi-async"]:
144143
raise ValueError("Value not one of 'async' or 'semi-async'")
@@ -147,7 +146,7 @@ def plugin_audit_strategy_validator(cls, value: str) -> Optional[str]:
147146

148147
@validator("logs_audit_policy")
149148
@classmethod
150-
def logs_audit_policy_validator(cls, value: str) -> Optional[str]:
149+
def logs_audit_policy_validator(cls, value: str) -> str | None:
151150
"""Check values for audit log policy."""
152151
valid_values = ["all", "logins", "queries"]
153152
if value not in valid_values:

src/mysql_vm_helpers.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import subprocess
1313
import tempfile
1414
import typing
15-
from typing import Any, Dict, Iterable, List, Optional, Tuple, Union
15+
from typing import Any, Iterable
1616

1717
import jinja2
1818
import pexpect
@@ -436,8 +436,8 @@ def wait_until_mysql_connection(self, check_port: bool = True) -> None:
436436
def execute_backup_commands( # type: ignore
437437
self,
438438
s3_directory: str,
439-
s3_parameters: Dict[str, str],
440-
) -> Tuple[str, str]:
439+
s3_parameters: dict[str, str],
440+
) -> tuple[str, str]:
441441
"""Executes commands to create a backup."""
442442
return super().execute_backup_commands(
443443
s3_directory,
@@ -465,13 +465,13 @@ def delete_temp_backup_directory( # type: ignore
465465
def retrieve_backup_with_xbcloud( # type: ignore
466466
self,
467467
backup_id: str,
468-
s3_parameters: Dict[str, str],
468+
s3_parameters: dict[str, str],
469469
temp_restore_directory: str = CHARMED_MYSQL_COMMON_DIRECTORY,
470470
xbcloud_location: str = CHARMED_MYSQL_XBCLOUD_LOCATION,
471471
xbstream_location: str = CHARMED_MYSQL_XBSTREAM_LOCATION,
472472
user=ROOT_SYSTEM_USER,
473473
group=ROOT_SYSTEM_USER,
474-
) -> Tuple[str, str, str]:
474+
) -> tuple[str, str, str]:
475475
"""Retrieve the provided backup with xbcloud."""
476476
return super().retrieve_backup_with_xbcloud(
477477
backup_id,
@@ -483,7 +483,7 @@ def retrieve_backup_with_xbcloud( # type: ignore
483483
group,
484484
)
485485

486-
def prepare_backup_for_restore(self, backup_location: str) -> Tuple[str, str]:
486+
def prepare_backup_for_restore(self, backup_location: str) -> tuple[str, str]:
487487
"""Prepare the download backup for restore with xtrabackup --prepare."""
488488
return super().prepare_backup_for_restore(
489489
backup_location,
@@ -504,7 +504,7 @@ def empty_data_files(self) -> None:
504504
def restore_backup(
505505
self,
506506
backup_location: str,
507-
) -> Tuple[str, str]:
507+
) -> tuple[str, str]:
508508
"""Restore the provided prepared backup."""
509509
# TODO: remove workaround for changing permissions and ownership of data
510510
# files once restore backup commands can be run with snap_daemon user
@@ -572,13 +572,13 @@ def delete_temp_restore_directory(self) -> None:
572572

573573
def _execute_commands(
574574
self,
575-
commands: List[str],
575+
commands: list[str],
576576
bash: bool = False,
577577
user: str = None,
578578
group: str = None,
579-
env_extra: Dict = {},
580-
stream_output: Optional[str] = None,
581-
) -> Tuple[str, str]:
579+
env_extra: dict = {},
580+
stream_output: str | None = None,
581+
) -> tuple[str, str]:
582582
"""Execute commands on the server where mysql is running.
583583
584584
Args:
@@ -802,10 +802,10 @@ def _run_mysqlsh_script(
802802

803803
def _run_mysqlcli_script(
804804
self,
805-
script: Union[Tuple[Any, ...], List[Any]],
805+
script: tuple[Any, ...] | list[Any],
806806
user: str = "root",
807-
password: Optional[str] = None,
808-
timeout: Optional[int] = None,
807+
password: str | None = None,
808+
timeout: int | None = None,
809809
exception_as_warning: bool = False,
810810
log_errors: bool = True,
811811
) -> list:
@@ -1001,7 +1001,7 @@ def write_content_to_file(
10011001
os.chmod(path, mode=permission)
10021002

10031003
@staticmethod
1004-
def fetch_error_log() -> Optional[str]:
1004+
def fetch_error_log() -> str | None:
10051005
"""Fetch the mysqld error log."""
10061006
if os.path.exists(f"{CHARMED_MYSQL_COMMON_DIRECTORY}/var/log/mysql/error.log"):
10071007
# can be empty if just rotated

src/relations/db_router.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import logging
88
import typing
99
from collections import namedtuple
10-
from typing import Dict, List, Set, Tuple
1110

1211
from charms.mysql.v0.mysql import (
1312
MySQLCheckUserExistenceError,
@@ -70,7 +69,7 @@ def _get_or_set_password_in_peer_databag(self, username: str) -> str:
7069

7170
def _get_requested_users_from_relation_databag(
7271
self, db_router_databag: RelationDataContent
73-
) -> List[RequestedUser]:
72+
) -> list[RequestedUser]:
7473
"""Retrieve requested user information from the db-router relation databag.
7574
7675
Args:
@@ -109,8 +108,8 @@ def _get_requested_users_from_relation_databag(
109108
return requested_users
110109

111110
def _create_requested_users(
112-
self, requested_users: List[RequestedUser], user_unit_name: str
113-
) -> Tuple[Dict[str, str], Set[str]]:
111+
self, requested_users: list[RequestedUser], user_unit_name: str
112+
) -> tuple[dict[str, str], set[str]]:
114113
"""Create the requested users and said user scoped databases.
115114
116115
Args:

0 commit comments

Comments
 (0)