Skip to content

Commit

Permalink
Merge branch 'main' into discourse-gatekeeper/migrate
Browse files Browse the repository at this point in the history
  • Loading branch information
izmalk authored Dec 18, 2024
2 parents a256b82 + 1c6b435 commit cf76af3
Show file tree
Hide file tree
Showing 13 changed files with 221 additions and 69 deletions.
85 changes: 65 additions & 20 deletions lib/charms/zookeeper/v0/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def update_cluster(new_members: List[str], event: EventBase) -> None:

# Increment this PATCH version before using `charmcraft publish-lib` or reset
# to 0 if you are raising the major API version
LIBPATCH = 6
LIBPATCH = 8


logger = logging.getLogger(__name__)
Expand All @@ -101,6 +101,12 @@ class QuorumLeaderNotFoundError(Exception):
pass


class NoUnitFoundError(Exception):
"""Generic exception for when there are no running zk unit in the app."""

pass


class ZooKeeperManager:
"""Handler for performing ZK commands."""

Expand All @@ -114,6 +120,7 @@ def __init__(
keyfile_path: Optional[str] = "",
keyfile_password: Optional[str] = "",
certfile_path: Optional[str] = "",
read_only: bool = True,
):
self.hosts = hosts
self.username = username
Expand All @@ -123,12 +130,21 @@ def __init__(
self.keyfile_path = keyfile_path
self.keyfile_password = keyfile_password
self.certfile_path = certfile_path
self.leader = ""
self.zk_host = ""
self.read_only = read_only

try:
self.leader = self.get_leader()
except RetryError:
raise QuorumLeaderNotFoundError("quorum leader not found")
if not read_only:
try:
self.zk_host = self.get_leader()
except RetryError:
raise QuorumLeaderNotFoundError("quorum leader not found")

else:
try:
self.zk_host = self.get_any_unit()

except RetryError:
raise NoUnitFoundError

@retry(
wait=wait_fixed(3),
Expand Down Expand Up @@ -170,6 +186,35 @@ def get_leader(self) -> str:

return leader or ""

@retry(
wait=wait_fixed(3),
stop=stop_after_attempt(2),
retry=retry_if_not_result(lambda result: True if result else False),
)
def get_any_unit(self) -> str:
any_host = None
for host in self.hosts:
try:
with ZooKeeperClient(
host=host,
client_port=self.client_port,
username=self.username,
password=self.password,
use_ssl=self.use_ssl,
keyfile_path=self.keyfile_path,
keyfile_password=self.keyfile_password,
certfile_path=self.certfile_path,
) as zk:
response = zk.srvr
if response:
any_host = host
break
except KazooTimeoutError: # in the case of having a dead unit in relation data
logger.debug(f"TIMEOUT - {host}")
continue

return any_host or ""

@property
def server_members(self) -> Set[str]:
"""The current members within the ZooKeeper quorum.
Expand All @@ -179,7 +224,7 @@ def server_members(self) -> Set[str]:
e.g {"server.1=10.141.78.207:2888:3888:participant;0.0.0.0:2181"}
"""
with ZooKeeperClient(
host=self.leader,
host=self.zk_host,
client_port=self.client_port,
username=self.username,
password=self.password,
Expand All @@ -200,7 +245,7 @@ def config_version(self) -> int:
The zookeeper config version decoded from base16
"""
with ZooKeeperClient(
host=self.leader,
host=self.zk_host,
client_port=self.client_port,
username=self.username,
password=self.password,
Expand All @@ -221,7 +266,7 @@ def members_syncing(self) -> bool:
True if any members are syncing. Otherwise False.
"""
with ZooKeeperClient(
host=self.leader,
host=self.zk_host,
client_port=self.client_port,
username=self.username,
password=self.password,
Expand Down Expand Up @@ -305,7 +350,7 @@ def add_members(self, members: Iterable[str]) -> None:

# specific connection to leader
with ZooKeeperClient(
host=self.leader,
host=self.zk_host,
client_port=self.client_port,
username=self.username,
password=self.password,
Expand All @@ -330,7 +375,7 @@ def remove_members(self, members: Iterable[str]) -> None:
for member in members:
member_id = re.findall(r"server.([0-9]+)", member)[0]
with ZooKeeperClient(
host=self.leader,
host=self.zk_host,
client_port=self.client_port,
username=self.username,
password=self.password,
Expand All @@ -356,7 +401,7 @@ def leader_znodes(self, path: str) -> Set[str]:
Set of all nested child zNodes
"""
with ZooKeeperClient(
host=self.leader,
host=self.zk_host,
client_port=self.client_port,
username=self.username,
password=self.password,
Expand All @@ -369,15 +414,15 @@ def leader_znodes(self, path: str) -> Set[str]:

return all_znode_children

def create_znode_leader(self, path: str, acls: List[ACL]) -> None:
def create_znode_leader(self, path: str, acls: List[ACL] | None = None) -> None:
"""Creates a new zNode on the current quorum leader with given ACLs.
Args:
path: the zNode path to set
acls: the ACLs to be set on that path
"""
with ZooKeeperClient(
host=self.leader,
host=self.zk_host,
client_port=self.client_port,
username=self.username,
password=self.password,
Expand All @@ -388,15 +433,15 @@ def create_znode_leader(self, path: str, acls: List[ACL]) -> None:
) as zk:
zk.create_znode(path=path, acls=acls)

def set_acls_znode_leader(self, path: str, acls: List[ACL]) -> None:
def set_acls_znode_leader(self, path: str, acls: List[ACL] | None = None) -> None:
"""Updates ACLs for an existing zNode on the current quorum leader.
Args:
path: the zNode path to update
acls: the new ACLs to be set on that path
"""
with ZooKeeperClient(
host=self.leader,
host=self.zk_host,
client_port=self.client_port,
username=self.username,
password=self.password,
Expand All @@ -414,7 +459,7 @@ def delete_znode_leader(self, path: str) -> None:
path: the zNode path to delete
"""
with ZooKeeperClient(
host=self.leader,
host=self.zk_host,
client_port=self.client_port,
username=self.username,
password=self.password,
Expand All @@ -432,7 +477,7 @@ def get_version(self) -> str:
String of ZooKeeper service version
"""
with ZooKeeperClient(
host=self.leader,
host=self.zk_host,
client_port=self.client_port,
username=self.username,
password=self.password,
Expand Down Expand Up @@ -577,7 +622,7 @@ def delete_znode(self, path: str) -> None:
return
self.client.delete(path, recursive=True)

def create_znode(self, path: str, acls: List[ACL]) -> None:
def create_znode(self, path: str, acls: List[ACL] | None = None) -> None:
"""Create new znode.
Args:
Expand All @@ -599,7 +644,7 @@ def get_acls(self, path: str) -> List[ACL]:

return acl_list if acl_list else []

def set_acls(self, path: str, acls: List[ACL]) -> None:
def set_acls(self, path: str, acls: List[ACL] | None = None) -> None:
"""Sets acls for a desired znode path.
Args:
Expand Down
6 changes: 3 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ cosl==0.0.24 ; python_version >= "3.8" and python_version < "4.0"
cryptography==43.0.3 ; python_version >= "3.8" and python_version < "4.0"
exceptiongroup==1.2.2 ; python_version >= "3.8" and python_version < "3.11"
h11==0.14.0 ; python_version >= "3.8" and python_version < "4.0"
httpcore==1.0.6 ; python_version >= "3.8" and python_version < "4.0"
httpcore==1.0.7 ; python_version >= "3.8" and python_version < "4.0"
httpx==0.27.2 ; python_version >= "3.8" and python_version < "4.0"
idna==3.10 ; python_version >= "3.8" and python_version < "4.0"
importlib-resources==6.4.5 ; python_version >= "3.8" and python_version < "3.9"
Expand All @@ -20,11 +20,11 @@ ops==2.17.0 ; python_version >= "3.8" and python_version < "4.0"
pkgutil-resolve-name==1.3.10 ; python_version >= "3.8" and python_version < "3.9"
pure-sasl==0.6.2 ; python_version >= "3.8" and python_version < "4.0"
pycparser==2.22 ; python_version >= "3.8" and python_version < "4.0" and platform_python_implementation != "PyPy"
pydantic==1.10.18 ; python_version >= "3.8" and python_version < "4.0"
pydantic==1.10.19 ; python_version >= "3.8" and python_version < "4.0"
pyyaml==6.0.2 ; python_version >= "3.8" and python_version < "4.0"
referencing==0.35.1 ; python_version >= "3.8" and python_version < "4.0"
requests==2.32.3 ; python_version >= "3.8" and python_version < "4.0"
rpds-py==0.18.1 ; python_version >= "3.8" and python_version < "4.0"
rpds-py==0.20.1 ; python_version >= "3.8" and python_version < "4.0"
sniffio==1.3.1 ; python_version >= "3.8" and python_version < "4.0"
tenacity==9.0.0 ; python_version >= "3.8" and python_version < "4.0"
typing-extensions==4.12.2 ; python_version >= "3.8" and python_version < "4.0"
Expand Down
9 changes: 9 additions & 0 deletions src/core/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
BROKER,
CONTROLLER,
CONTROLLER_PORT,
CONTROLLER_USER,
INTERNAL_USERS,
KRAFT_NODE_ID_OFFSET,
MIN_REPLICAS,
Expand All @@ -65,10 +66,12 @@
setattr(custom_secret_groups, "BROKER", "broker")
setattr(custom_secret_groups, "BALANCER", "balancer")
setattr(custom_secret_groups, "ZOOKEEPER", "zookeeper")
setattr(custom_secret_groups, "CONTROLLER", "controller")

SECRET_LABEL_MAP = {
"broker-username": getattr(custom_secret_groups, "BROKER"),
"broker-password": getattr(custom_secret_groups, "BROKER"),
"controller-password": getattr(custom_secret_groups, "CONTROLLER"),
"broker-uris": getattr(custom_secret_groups, "BROKER"),
"zk-username": getattr(custom_secret_groups, "ZOOKEEPER"),
"zk-password": getattr(custom_secret_groups, "ZOOKEEPER"),
Expand Down Expand Up @@ -157,6 +160,7 @@ def peer_cluster_orchestrator(self) -> PeerCluster:
extra_kwargs.update(
{
"controller_quorum_uris": self.cluster.controller_quorum_uris,
"controller_password": self.cluster.controller_password,
}
)

Expand All @@ -178,6 +182,7 @@ def peer_cluster(self) -> PeerCluster:
"balancer_password": self.cluster.balancer_password,
"balancer_uris": self.cluster.balancer_uris,
"controller_quorum_uris": self.cluster.controller_quorum_uris,
"controller_password": self.cluster.controller_password,
}
)

Expand Down Expand Up @@ -323,6 +328,10 @@ def super_users(self) -> str:
Semicolon delimited string of current super users
"""
super_users = set(INTERNAL_USERS)

if self.kraft_mode:
super_users.add(CONTROLLER_USER)

for relation in self.client_relations:
if not relation or not relation.app:
continue
Expand Down
Loading

0 comments on commit cf76af3

Please sign in to comment.