added automatic chrony management

This commit is contained in:
study-faraphel 2025-02-03 09:51:09 +01:00
parent 9480339b89
commit 90745b069c
4 changed files with 45 additions and 36 deletions

View file

@ -25,3 +25,7 @@ class PeerEvent(base.BaseEvent):
# make sure we trust the peers trusted by this peer
for public_key_hash in peer.allowed_public_key_hashes:
self.manager.communication.trust_peer_hash(public_key_hash)
# add the peer as a time source and allow it to use us as a time source
self.manager.clock.add_source(address[0])
self.manager.clock.allow_client(address[0])

View file

@ -1,57 +1,59 @@
import subprocess
import typing
from source import managers
class BatmanController:
# TODO: need to be able to get ping in the network if possible, otherwise no other uses
def __init__(self):
pass
class ChronyController:
class ChronyManager:
"""
Wrapper to control chrony to manipulate time synchronisation
Manager for chrony to manipulate time synchronisation
NOTE: the ideal method would be to use `chronyd.sock` to communicate, but it seems to only work with raw binary data
"""
def __init__(self):
def __init__(self, manager: "managers.Manager"):
self.manager = manager
self.clear_sources()
self.deny_client("all")
@staticmethod
def run_command(*args: str) -> str:
# run the command through the chrony command line tool
# NOTE(Faraphel): do not check the errors because some codes like 511 can happen
# if we add a source that already exist
process = subprocess.run(
["chronyc", *args],
stdout=subprocess.PIPE,
)
# raise an error if the command did not ended up successfully
process.check_returncode()
# return the stdout of the command
return process.stdout.decode()
def get_sources(self) -> list[...]:
def get_sources(self) -> typing.Iterator[str]:
"""
Get the list of NTP sources
:return: the list of NTP sources
"""
...
table: str = self.run_command("sources")
sources_info = table.strip().split("\n")[2:]
print(sources_info)
for source_info in sources_info:
yield source_info.split(" ")[1]
def add_source(self, kind: str, source: ...) -> None:
def add_source(self, address: str) -> None:
"""
Add a source to chrony
"""
self.run_command("add", "server", host, "iburst")
self.run_command("add", "server", address, "iburst")
def remove_source(self, source: ...) -> None:
def remove_source(self, address: str) -> None:
"""
Remove a source from chrony
"""
...
self.run_command("delete", address)
def clear_sources(self) -> None:
"""
@ -61,34 +63,39 @@ class ChronyController:
for source in self.get_sources():
self.remove_source(source)
def get_clients(self) -> list[...]:
def get_clients(self) -> typing.Iterator[str]:
"""
Get the list of clients using us as a server
:return: the list of clients
"""
...
table: str = self.run_command("clients")
clients_info = table.strip().split("\n")[2:]
for client_info in clients_info:
yield client_info.split(" ")[0]
def allow_client(self, client: ...) -> None:
def allow_client(self, address: str) -> None:
"""
Allow a client to use us as a server
:param client: the client information
:param address: the client address
"""
...
self.run_command("allow", address)
def allow_all_clients(self) -> None:
"""
Allow all clients to use us as a time-server
"""
def deny_client(self, client: ...) -> None:
self.allow_client("all")
def deny_client(self, address: str) -> None:
"""
Deny a client to use us as a server
:param client: the client information
:param address: the client address
"""
...
self.run_command("deny", address)
def deny_all_clients(self) -> None:
"""
@ -96,11 +103,3 @@ class ChronyController:
"""
self.deny_client("all")
if __name__ == "__main__":
chrony = ChronyController()
while True:
command = input("chronyc >>> ")
print(chrony.run_command(command))

View file

@ -3,7 +3,6 @@ from pathlib import Path
from source import packets
from source.behaviors import events
from source.managers.ApiManager import ApiManager
class Manager:
@ -12,11 +11,17 @@ class Manager:
"""
def __init__(self, interface: str):
from . import CommunicationManager, EventManager, RoleManager, AudioManager, PeerManager, DriveManager
from . import (
CommunicationManager, EventManager, RoleManager, AudioManager, PeerManager,
DriveManager, ChronyManager, ApiManager
)
self.storage = Path("./storage/")
self.storage.mkdir(exist_ok=True)
# clock manager
self.clock = ChronyManager(self)
# communication manager
self.communication = CommunicationManager(self, interface)
self.communication.register_packet_type(b"DISC", packets.DiscoveryPacket)

View file

@ -5,5 +5,6 @@ from .AudioManager import AudioManager
from .PeerManager import PeerManager
from .DriveManager import DriveManager
from .ApiManager import ApiManager
from .ChronyManager import ChronyManager
from .Manager import Manager