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 # make sure we trust the peers trusted by this peer
for public_key_hash in peer.allowed_public_key_hashes: for public_key_hash in peer.allowed_public_key_hashes:
self.manager.communication.trust_peer_hash(public_key_hash) 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 subprocess
import typing
from source import managers
class BatmanController: class ChronyManager:
# TODO: need to be able to get ping in the network if possible, otherwise no other uses
def __init__(self):
pass
class ChronyController:
""" """
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 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.clear_sources()
self.deny_client("all") self.deny_client("all")
@staticmethod @staticmethod
def run_command(*args: str) -> str: def run_command(*args: str) -> str:
# run the command through the chrony command line tool # 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( process = subprocess.run(
["chronyc", *args], ["chronyc", *args],
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
) )
# raise an error if the command did not ended up successfully
process.check_returncode()
# return the stdout of the command # return the stdout of the command
return process.stdout.decode() return process.stdout.decode()
def get_sources(self) -> list[...]: def get_sources(self) -> typing.Iterator[str]:
""" """
Get the list of NTP sources Get the list of NTP sources
:return: 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 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 Remove a source from chrony
""" """
... self.run_command("delete", address)
def clear_sources(self) -> None: def clear_sources(self) -> None:
""" """
@ -61,34 +63,39 @@ class ChronyController:
for source in self.get_sources(): for source in self.get_sources():
self.remove_source(source) 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 Get the list of clients using us as a server
:return: the list of clients :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 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: def allow_all_clients(self) -> None:
""" """
Allow all clients to use us as a time-server 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 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: def deny_all_clients(self) -> None:
""" """
@ -96,11 +103,3 @@ class ChronyController:
""" """
self.deny_client("all") 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 import packets
from source.behaviors import events from source.behaviors import events
from source.managers.ApiManager import ApiManager
class Manager: class Manager:
@ -12,11 +11,17 @@ class Manager:
""" """
def __init__(self, interface: str): 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 = Path("./storage/")
self.storage.mkdir(exist_ok=True) self.storage.mkdir(exist_ok=True)
# clock manager
self.clock = ChronyManager(self)
# communication manager # communication manager
self.communication = CommunicationManager(self, interface) self.communication = CommunicationManager(self, interface)
self.communication.register_packet_type(b"DISC", packets.DiscoveryPacket) self.communication.register_packet_type(b"DISC", packets.DiscoveryPacket)

View file

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