From a3e9b450507b1cb8f88e8f8039f96b6ba204db49 Mon Sep 17 00:00:00 2001 From: Pranav Jerry Date: Mon, 6 Sep 2021 12:23:07 +0530 Subject: [PATCH 01/10] more logging messages and code cleanup Removed log messages from config.py --- naxalnet/__init__.py | 2 +- naxalnet/config.py | 9 +++++---- naxalnet/iwd.py | 2 ++ naxalnet/scripts.py | 15 ++++++++------- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/naxalnet/__init__.py b/naxalnet/__init__.py index 27c93ba..2160232 100644 --- a/naxalnet/__init__.py +++ b/naxalnet/__init__.py @@ -36,4 +36,4 @@ See README.md for documentation. # # In case you forgot to change the version, skip the number # and put the next number in the next commit. -__version__ = "0.3.0a2" +__version__ = "0.3.0a2.dev1" diff --git a/naxalnet/config.py b/naxalnet/config.py index 38a7a16..711166b 100644 --- a/naxalnet/config.py +++ b/naxalnet/config.py @@ -46,7 +46,8 @@ from pathlib import Path from configparser import ConfigParser from argparse import ArgumentParser, Namespace from naxalnet.default import CONFIG, CONFIG_FILES, CONFIG_DIRS -from naxalnet.log import logger + +# from naxalnet.log import logger def get_config_files(): @@ -70,14 +71,14 @@ def parse_config(): Parse all configuration files, with the values in default.py as fallback """ - logger.debug("Parsing config files") + # logger.debug("Parsing config files") parser = ConfigParser() # encoded defaults parser.read_dict(CONFIG) # read config files files = get_config_files() for i in files: - logger.debug("Reading config file %s", str(i)) + # logger.debug("Reading config file %s", str(i)) parser.read_file(i.open()) return parser @@ -145,5 +146,5 @@ def parse_args() -> Namespace: help="prints the version and exit", ) - logger.debug("Parsing arguments") + # logger.debug("Parsing arguments") return parser.parse_args() diff --git a/naxalnet/iwd.py b/naxalnet/iwd.py index b9eb90c..e15d660 100644 --- a/naxalnet/iwd.py +++ b/naxalnet/iwd.py @@ -310,11 +310,13 @@ class Adapter: """power on the adapter""" self._proxy.Powered = True logger.debug("Powered on adapter %s", self.name) + self.reload() def power_off(self): """power off the adapter""" self._proxy.Powered = False logger.debug("Powered off adapter %s", self.name) + self.reload() def supports_mode(self, mode: str) -> bool: """ diff --git a/naxalnet/scripts.py b/naxalnet/scripts.py index ce2d268..18086cf 100644 --- a/naxalnet/scripts.py +++ b/naxalnet/scripts.py @@ -99,7 +99,6 @@ def setup_devices(args): if not adhoc_adapter.is_powered_on(): logger.debug("Adapter %s is off. Turning on", adhoc_adapter.name) adhoc_adapter.power_on() - adhoc_device.reload() adhoc_device.start_adhoc_open(args.adhoc_name) # Start Access point if ap_device is not empty, # ie, we have more devices @@ -113,11 +112,13 @@ def setup_devices(args): if not ap_adapter.is_powered_on(): logger.debug("Adapter %s is off. Turning on", ap_adapter.name) ap_adapter.power_on() - ap_adapter.reload() ap_device.start_ap(args.ap_ssid, args.ap_passwd) - - # naxalnet prints Bye if no errors occured - logger.info("Bye") + else: + logger.info("Not setting up WiFi AP.") + else: + logger.warning( + "No device found to setup mesh. Make sure a WiFi adapter is connected" + ) def print_wifi(args): @@ -161,5 +162,5 @@ def here_be_dragons(): except DBusError: logger.exception("Error while communicating with iwd") sys.exit(4) - - logger.debug("Finished.") + # naxalnet prints Bye if no errors occured + logger.info("Bye") From 2d9aee4d3a3c975c30f3056c818e3dfba17963bc Mon Sep 17 00:00:00 2001 From: Pranav Jerry Date: Mon, 6 Sep 2021 14:57:54 +0530 Subject: [PATCH 02/10] added --systemd and --verbose arguments When run without --systemd, naxalnet will log to stderr. Otherwise, it will log to systemd journal. log.py is no longer needed. --- naxalnet.service | 2 +- naxalnet/__init__.py | 2 +- naxalnet/config.py | 11 +++++++++++ naxalnet/iwd.py | 5 ++++- naxalnet/log.py | 21 ++++++++++++++++++--- naxalnet/scripts.py | 22 +++++++++++++++++++++- 6 files changed, 56 insertions(+), 7 deletions(-) diff --git a/naxalnet.service b/naxalnet.service index 4280cfd..78cbee3 100644 --- a/naxalnet.service +++ b/naxalnet.service @@ -27,7 +27,7 @@ RestartSec=2sec # naxalnet cannot start a mesh network but exits without errors. # So, we give a 2s delay. ExecStartPre=/usr/bin/sleep 2 -ExecStart=/usr/bin/naxalnet +ExecStart=/usr/bin/naxalnet --systemd # Reload systemd-networkd after naxalnet exits ExecStartPost=/usr/bin/networkctl reload # Delete all files starting with mesh.* in /run/systemd/network diff --git a/naxalnet/__init__.py b/naxalnet/__init__.py index 2160232..15a69d5 100644 --- a/naxalnet/__init__.py +++ b/naxalnet/__init__.py @@ -36,4 +36,4 @@ See README.md for documentation. # # In case you forgot to change the version, skip the number # and put the next number in the next commit. -__version__ = "0.3.0a2.dev1" +__version__ = "0.3.0a2.dev2" diff --git a/naxalnet/config.py b/naxalnet/config.py index 711166b..2c72b5f 100644 --- a/naxalnet/config.py +++ b/naxalnet/config.py @@ -139,6 +139,13 @@ def parse_args() -> Namespace: help="volatile directory where configuration files of systemd-networkd should be copied", ) + parser.add_argument( + "--systemd", + action="store_true", + default=False, + help="send log messages to systemd journal", + ) + parser.add_argument( "--version", default=False, @@ -146,5 +153,9 @@ def parse_args() -> Namespace: help="prints the version and exit", ) + parser.add_argument( + "-v", "--verbose", action="count", default=0, help="increase output verbosity" + ) + # logger.debug("Parsing arguments") return parser.parse_args() diff --git a/naxalnet/iwd.py b/naxalnet/iwd.py index e15d660..e85e990 100644 --- a/naxalnet/iwd.py +++ b/naxalnet/iwd.py @@ -58,8 +58,11 @@ and what they mean: - node: a machine that runs naxalnet and is therefore connected to the mesh. """ +import logging from dasbus.connection import SystemMessageBus -from naxalnet.log import logger + +# from naxalnet.log import logger +logger = logging.getLogger(__name__) IWD_BUS = "net.connman.iwd" IWD_ROOT_PATH = "/" diff --git a/naxalnet/log.py b/naxalnet/log.py index 75c2a9c..1aa93a2 100644 --- a/naxalnet/log.py +++ b/naxalnet/log.py @@ -10,7 +10,22 @@ to the systemd journal import logging from systemd import journal +from naxalnet.config import parse_args -logger = logging.getLogger(__name__) -logger.setLevel(logging.DEBUG) -logger.addHandler(journal.JournalHandler()) + +def get_logger(): + """returns the logger object for logging""" + + args = parse_args() + if args.systemd: + logger = logging.getLogger(__name__) + logger.setLevel(logging.DEBUG) + logger.addHandler(journal.JournalHandler()) + else: + # logging.basicConfig(level=logging.DEBUG) + logger = logging.getLogger(__name__) + logger.setLevel(logging.DEBUG) + return logger + + +logger = get_logger() diff --git a/naxalnet/scripts.py b/naxalnet/scripts.py index 18086cf..6b7a6d7 100644 --- a/naxalnet/scripts.py +++ b/naxalnet/scripts.py @@ -28,13 +28,18 @@ When run from the commandline, the function here_be_dragons() is called. """ import sys +import logging from pathlib import Path from shutil import copy from dasbus.error import DBusError +from systemd import journal from naxalnet import __version__ from naxalnet.iwd import Adapter, Device, IWD from naxalnet.config import parse_args -from naxalnet.log import logger + +# from naxalnet.log import logger + +logger = logging.getLogger(__name__) def copy_files(args): @@ -144,6 +149,21 @@ def here_be_dragons(): """ args = parse_args() + # --verbose + if args.verbose >= 2: + loglevel = logging.DEBUG + elif args.verbose == 1: + loglevel = logging.INFO + else: + loglevel = logging.WARNING + + # if --systemd is given, log to systemd journal + if args.systemd: + logger.setLevel(level=logging.DEBUG) + logger.addHandler(journal.JournalHandler()) + else: + logging.basicConfig(level=loglevel) + if args.print_wifi: print_wifi(args) sys.exit(0) From 0bcd31b6e3495e12c0f78b04c5158db074ea00ca Mon Sep 17 00:00:00 2001 From: Pranav Jerry Date: Mon, 6 Sep 2021 15:00:34 +0530 Subject: [PATCH 03/10] removed log.py --- naxalnet/log.py | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 naxalnet/log.py diff --git a/naxalnet/log.py b/naxalnet/log.py deleted file mode 100644 index 1aa93a2..0000000 --- a/naxalnet/log.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python3 - -""" -log.py ------- - -This file contains the logger object, which is required for logging -to the systemd journal -""" - -import logging -from systemd import journal -from naxalnet.config import parse_args - - -def get_logger(): - """returns the logger object for logging""" - - args = parse_args() - if args.systemd: - logger = logging.getLogger(__name__) - logger.setLevel(logging.DEBUG) - logger.addHandler(journal.JournalHandler()) - else: - # logging.basicConfig(level=logging.DEBUG) - logger = logging.getLogger(__name__) - logger.setLevel(logging.DEBUG) - return logger - - -logger = get_logger() From 6fff558405111cf4cb094262300e4f2d2472bd9c Mon Sep 17 00:00:00 2001 From: Pranav Jerry Date: Mon, 6 Sep 2021 21:54:24 +0530 Subject: [PATCH 04/10] many changes, see full commit message - Renamed here_be_dragons() to main(). - Added daemon.py (doesn't do anything yet). - Added GPL disclaimer to all python files and removed the shebang #! from all files. - args is now defined outside any function in scripts.py - Changed arguments of some functions in scripts.py --- CHANGELOG.md | 13 ++-- naxalnet/__init__.py | 5 +- naxalnet/__main__.py | 8 +- naxalnet/config.py | 16 +++- naxalnet/daemon.py | 59 +++++++++++++++ naxalnet/default.py | 16 +++- naxalnet/iwd.py | 4 +- naxalnet/scripts.py | 169 +++++++++++++++++++++---------------------- setup.cfg | 2 +- 9 files changed, 188 insertions(+), 104 deletions(-) create mode 100644 naxalnet/daemon.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c418eb..c2538b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,12 @@ # Changelog -## [Unreleased][] - 2021-09-05 +## [Unreleased][] - 2021-09-06 -- Now logs to systemd journal. New dependency - `python3-systemd` +- **Logging**: logs to systemd journal when run from systemd, stderr + otherwise. +- New dependency `python3-systemd` - Fixed dependency order in systemd service +- Added `--verbose` argument ## [v0.3.0][] - 2021-08-19 @@ -22,9 +25,9 @@ ## [v0.1.0][] - 2021-06-19 -Initial version. At first, this was a shell script. Than it was converted -into a single python file that did just what the shell script used to do. -The shell script was not given a version. +Initial python version. At first, this was a shell script. Than it was +converted into a single python file that did just what the shell script +used to do. The shell script was not given a version. [unreleased]: https://git.disroot.org/pranav/naxalnet/compare/v0.3.0...HEAD [v0.3.0]: https://git.disroot.org/pranav/naxalnet/compare/v0.2.0...v0.3.0 diff --git a/naxalnet/__init__.py b/naxalnet/__init__.py index 15a69d5..b20beec 100644 --- a/naxalnet/__init__.py +++ b/naxalnet/__init__.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python3 - +# This file is part of naxalnet. # Copyright (C) 2021 The naxalnet Authors # This program is free software: you can redistribute it and/or modify @@ -36,4 +35,4 @@ See README.md for documentation. # # In case you forgot to change the version, skip the number # and put the next number in the next commit. -__version__ = "0.3.0a2.dev2" +__version__ = "0.3.0a2.dev3" diff --git a/naxalnet/__main__.py b/naxalnet/__main__.py index 70456a6..cde1430 100644 --- a/naxalnet/__main__.py +++ b/naxalnet/__main__.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python3 - +# This file is part of naxalnet. # Copyright (C) 2021 The naxalnet Authors # This program is free software: you can redistribute it and/or modify @@ -15,13 +14,14 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . + """ If called as python -m naxalnet, this file makes naxalnet run like it was called from the commandline. Try: python -m naxalnet --help """ -from naxalnet.scripts import here_be_dragons +from naxalnet.scripts import main if __name__ == "__main__": - here_be_dragons() + main() diff --git a/naxalnet/config.py b/naxalnet/config.py index 2c72b5f..f541cda 100644 --- a/naxalnet/config.py +++ b/naxalnet/config.py @@ -1,4 +1,18 @@ -#!/usr/bin/env python3 +# This file is part of naxalnet. +# Copyright (C) 2021 The naxalnet Authors + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ config.py diff --git a/naxalnet/daemon.py b/naxalnet/daemon.py new file mode 100644 index 0000000..9d539f5 --- /dev/null +++ b/naxalnet/daemon.py @@ -0,0 +1,59 @@ +# This file is part of naxalnet. +# Copyright (C) 2021 The naxalnet Authors + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +daemon.py +--------- + +The daemon part. This is currently under construction. +""" + +import logging +from naxalnet.iwd import IWD + + +class Daemon: + """implements the daemon part""" + + logger = logging.getLogger(__name__) + + def __init__(self): + iwd = IWD() + self.device_add_call = self.device_remove_call = None + + def on_device_add(self, callback): + """ + run the given callback with no arguments + every time a device is added + """ + self.device_add_call = callback + + def on_device_remove(self, callback): + """ + run the given callback with no arguments + every time a device is removed + """ + self.device_remove_call = callback + + def register_callbacks(self): + """ + register the callbacks with D-Bus + """ + + def start(self): + """ + start the daemon + """ diff --git a/naxalnet/default.py b/naxalnet/default.py index 798e386..74c8076 100644 --- a/naxalnet/default.py +++ b/naxalnet/default.py @@ -1,4 +1,18 @@ -#!/usr/bin/env python3 +# This file is part of naxalnet. +# Copyright (C) 2021 The naxalnet Authors + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ default.py diff --git a/naxalnet/iwd.py b/naxalnet/iwd.py index e85e990..19b87b5 100644 --- a/naxalnet/iwd.py +++ b/naxalnet/iwd.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python3 - +# This file is part of naxalnet. # Copyright (C) 2021 The naxalnet Authors # This program is free software: you can redistribute it and/or modify @@ -15,7 +14,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . - """ iwd.py ------ diff --git a/naxalnet/scripts.py b/naxalnet/scripts.py index 6b7a6d7..99ae572 100644 --- a/naxalnet/scripts.py +++ b/naxalnet/scripts.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python3 - +# This file is part of naxalnet. # Copyright (C) 2021 The naxalnet Authors # This program is free software: you can redistribute it and/or modify @@ -24,7 +23,7 @@ and doing the things this program is supposed to do. This file is named scripts.py because the original developer of this program could not think of a better name that suits this file. If you want to hack naxalnet, this is the right place to start. -When run from the commandline, the function here_be_dragons() is called. +When run from the commandline, the function main() is called. """ import sys @@ -40,93 +39,100 @@ from naxalnet.config import parse_args # from naxalnet.log import logger logger = logging.getLogger(__name__) +args = parse_args() -def copy_files(args): +def copy_files(): """ Copy networkd configs to volatile dir. The D-Bus API does not support creating new interfaces or linking to bridges. So we use config files. See man:systemd.network(5) """ + try: + logger.info("Copying network config files") + dest = Path(args.networkd_runtime_dir) + src = Path(args.networkd_config_dir) - logger.info("Copying network config files") - dest = Path(args.networkd_runtime_dir) - src = Path(args.networkd_config_dir) + # Create the volatile directory if it doesn't exist + dest.mkdir(parents=True, exist_ok=True) - # Create the volatile directory if it doesn't exist - dest.mkdir(parents=True, exist_ok=True) - - # Copy all files in src to dest - for i in src.iterdir(): - copy(i, dest) + # Copy all files in src to dest + for i in src.iterdir(): + copy(i, dest) + except PermissionError as error: + logger.error("Cannot copy file: %s", error) + sys.exit(3) -def setup_devices(args): +def setup_devices(): """ Setup wifi interfaces using iwd This function should be called every time an interface is connected or removed. - args should be what parse_args() returns """ - iwd = IWD() - devices = iwd.get_devices() - adhoc_devices = [] - ap_devices = [] + try: + iwd = IWD() + devices = iwd.get_devices() + adhoc_devices = [] + ap_devices = [] - # Find devices supporting ad-hoc and ap - for i in devices: - # For each device, check if its adapter supports - # ad-hoc or ap. Many adapters will support both, - # so we will prioritise ad-hoc over ap. - device = Device(i) - logger.debug("Found device %s", device.name) - adapter = Adapter(device.adapter) - if adapter.supports_mode("ad-hoc"): - logger.debug("The device %s can be used for ad-hoc", device.name) - adhoc_devices.append(i) - if adapter.supports_mode("ap"): - logger.debug("The device %s can be used for ap", device.name) - ap_devices.append(i) + # Find devices supporting ad-hoc and ap + for i in devices: + # For each device, check if its adapter supports + # ad-hoc or ap. Many adapters will support both, + # so we will prioritise ad-hoc over ap. + device = Device(i) + logger.debug("Found device %s", device.name) + adapter = Adapter(device.adapter) + if adapter.supports_mode("ad-hoc"): + logger.debug("The device %s can be used for ad-hoc", device.name) + adhoc_devices.append(i) + if adapter.supports_mode("ap"): + logger.debug("The device %s can be used for ap", device.name) + ap_devices.append(i) - if len(adhoc_devices) != 0: - # Start ad-hoc on first device supporting ad-hoc - adhoc_device = Device(adhoc_devices.pop()) - # The same device is likely to have ap support too. - # But we can't start ad-hoc and ap on the same interface. - # So we will remove adhoc_device from ap_devices if it exists there - if adhoc_device.name in ap_devices: - ap_devices.remove(adhoc_device.name) - logger.info("Starting mesh on %s", adhoc_device.name) - # Turn on adapter if it is off - # See issue #9 - adhoc_adapter = Adapter(adhoc_device.adapter) - if not adhoc_adapter.is_powered_on(): - logger.debug("Adapter %s is off. Turning on", adhoc_adapter.name) - adhoc_adapter.power_on() - adhoc_device.start_adhoc_open(args.adhoc_name) - # Start Access point if ap_device is not empty, - # ie, we have more devices - if len(ap_devices) != 0: - ap_device = Device(ap_devices.pop()) - logger.info("Starting WiFi Access Point on %s", ap_device.name) - logger.info("Use naxalnet --print-wifi to get password") - # Turn on adapter if it is off - # See issue #9 - ap_adapter = Adapter(ap_device.adapter) - if not ap_adapter.is_powered_on(): - logger.debug("Adapter %s is off. Turning on", ap_adapter.name) - ap_adapter.power_on() - ap_device.start_ap(args.ap_ssid, args.ap_passwd) + if len(adhoc_devices) != 0: + # Start ad-hoc on first device supporting ad-hoc + adhoc_device = Device(adhoc_devices.pop()) + # The same device is likely to have ap support too. + # But we can't start ad-hoc and ap on the same interface. + # So we will remove adhoc_device from ap_devices if it exists there + if adhoc_device.name in ap_devices: + ap_devices.remove(adhoc_device.name) + logger.info("Starting mesh on %s", adhoc_device.name) + # Turn on adapter if it is off + # See issue #9 + adhoc_adapter = Adapter(adhoc_device.adapter) + if not adhoc_adapter.is_powered_on(): + logger.debug("Adapter %s is off. Turning on", adhoc_adapter.name) + adhoc_adapter.power_on() + adhoc_device.start_adhoc_open(args.adhoc_name) + # Start Access point if ap_device is not empty, + # ie, we have more devices + if len(ap_devices) != 0: + ap_device = Device(ap_devices.pop()) + logger.info("Starting WiFi Access Point on %s", ap_device.name) + logger.info("Use naxalnet --print-wifi to get password") + # Turn on adapter if it is off + # See issue #9 + ap_adapter = Adapter(ap_device.adapter) + if not ap_adapter.is_powered_on(): + logger.debug("Adapter %s is off. Turning on", ap_adapter.name) + ap_adapter.power_on() + ap_device.start_ap(args.ap_ssid, args.ap_passwd) + else: + logger.info("Not setting up WiFi AP.") else: - logger.info("Not setting up WiFi AP.") - else: - logger.warning( - "No device found to setup mesh. Make sure a WiFi adapter is connected" - ) + logger.warning( + "No device found to setup mesh. Make sure a WiFi adapter is connected" + ) + except DBusError: + logger.exception("Error while communicating with iwd") + sys.exit(4) -def print_wifi(args): +def print_wifi(): """ Prints the name and password of the adhoc, and ap from the arguments @@ -141,14 +147,19 @@ def print_version(): print(__version__) -def here_be_dragons(): +def main(): """ This is where the magic happens! This function is run every time you execute naxalnet from the commandline """ - args = parse_args() + if args.print_wifi: + print_wifi() + sys.exit(0) + elif args.version: + print_version() + sys.exit(0) # --verbose if args.verbose >= 2: loglevel = logging.DEBUG @@ -164,23 +175,9 @@ def here_be_dragons(): else: logging.basicConfig(level=loglevel) - if args.print_wifi: - print_wifi(args) - sys.exit(0) - elif args.version: - print_version() - sys.exit(0) + copy_files() - try: - copy_files(args) - except PermissionError as error: - logger.error("Cannot copy file: %s", error) - sys.exit(3) + setup_devices() - try: - setup_devices(args) - except DBusError: - logger.exception("Error while communicating with iwd") - sys.exit(4) # naxalnet prints Bye if no errors occured logger.info("Bye") diff --git a/setup.cfg b/setup.cfg index df3c1e4..d06bda0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -27,7 +27,7 @@ install_requires = [options.entry_points] console_scripts = - naxalnet = naxalnet.scripts:here_be_dragons + naxalnet = naxalnet.scripts:main [options.data_files] lib/systemd/system = From 68b53ccad10c785ffbbe659c680a68edf19243ab Mon Sep 17 00:00:00 2001 From: Pranav Jerry Date: Tue, 7 Sep 2021 11:19:14 +0530 Subject: [PATCH 05/10] implemented daemon naxalnet is now a daemon! When run from systemd, it checks for new devices or removal of devices and reloads the wifi configuration. Updated the systemd service and changed Type to notify. Unfortunately, there is some problem with logging. The messages from naxalnet.iwd could not be found in the systemd journal or while running without --systemd. --- naxalnet.service | 19 +++++++------------ naxalnet/__init__.py | 2 +- naxalnet/config.py | 2 -- naxalnet/daemon.py | 42 +++++++++++++++++++++++++++--------------- naxalnet/iwd.py | 1 - naxalnet/scripts.py | 29 +++++++++++++++++++++++------ 6 files changed, 58 insertions(+), 37 deletions(-) diff --git a/naxalnet.service b/naxalnet.service index 78cbee3..624f8c3 100644 --- a/naxalnet.service +++ b/naxalnet.service @@ -17,28 +17,23 @@ After=NetworkManager.service After=wpa_supplicant.service [Service] -# TODO: change to notify when naxalnet becomes a daemon -Type=oneshot -RemainAfterExit=yes +Type=notify +NotifyAccess=all Restart=on-failure RestartSec=2sec -# IWD takes some time to find devices. -# If naxalnet is run before iwd finds devices, -# naxalnet cannot start a mesh network but exits without errors. -# So, we give a 2s delay. -ExecStartPre=/usr/bin/sleep 2 ExecStart=/usr/bin/naxalnet --systemd # Reload systemd-networkd after naxalnet exits ExecStartPost=/usr/bin/networkctl reload # Delete all files starting with mesh.* in /run/systemd/network -ExecStop=/usr/bin/find /run/systemd/network -type f -delete -name "mesh.*" +ExecStopPost=/usr/bin/find /run/systemd/network -type f -delete -name "mesh.*" # Delete the interfaces created... ExecStopPost=/usr/bin/networkctl delete bridge0 bat0 # ... and reload the configuration files. ExecStopPost=/usr/bin/networkctl reload - -# Disable python buffering -Environment=PYTHONUNBUFFERED=1 +# naxalnet already logs to systemd journal so we don't need +# stdout and stderr. +StandardOutput=null +StandardError=null [Install] WantedBy=multi-user.target diff --git a/naxalnet/__init__.py b/naxalnet/__init__.py index b20beec..7151a24 100644 --- a/naxalnet/__init__.py +++ b/naxalnet/__init__.py @@ -35,4 +35,4 @@ See README.md for documentation. # # In case you forgot to change the version, skip the number # and put the next number in the next commit. -__version__ = "0.3.0a2.dev3" +__version__ = "0.3.0a2.dev4" diff --git a/naxalnet/config.py b/naxalnet/config.py index f541cda..34cb551 100644 --- a/naxalnet/config.py +++ b/naxalnet/config.py @@ -61,8 +61,6 @@ from configparser import ConfigParser from argparse import ArgumentParser, Namespace from naxalnet.default import CONFIG, CONFIG_FILES, CONFIG_DIRS -# from naxalnet.log import logger - def get_config_files(): """ diff --git a/naxalnet/daemon.py b/naxalnet/daemon.py index 9d539f5..a04a47d 100644 --- a/naxalnet/daemon.py +++ b/naxalnet/daemon.py @@ -22,38 +22,50 @@ The daemon part. This is currently under construction. """ import logging -from naxalnet.iwd import IWD +from dasbus.loop import EventLoop +from naxalnet.iwd import IWD, IWD_DEVICE_INTERFACE + +logger = logging.getLogger(__name__) class Daemon: """implements the daemon part""" - logger = logging.getLogger(__name__) - def __init__(self): - iwd = IWD() - self.device_add_call = self.device_remove_call = None + self.loop = EventLoop() + self.iwd = IWD() - def on_device_add(self, callback): + def on_device_add(self, path, data): """ - run the given callback with no arguments - every time a device is added + this function will be run every time a device is added """ - self.device_add_call = callback + if IWD_DEVICE_INTERFACE in data: + logger.debug("New device %s found", str(data[IWD_DEVICE_INTERFACE]["Name"])) + logger.info("Reloading") + self.callback() - def on_device_remove(self, callback): + def on_device_remove(self, path, data): """ - run the given callback with no arguments - every time a device is removed + this function will be run every time a device is removed """ - self.device_remove_call = callback + if IWD_DEVICE_INTERFACE in data: + logger.debug("A device was removed") + logger.info("Reloading") + self.callback() - def register_callbacks(self): + def add_callback(self, callback): """ - register the callbacks with D-Bus + register the callback with D-Bus so that callback is + run every time a device is added or removed """ + self.callback = callback + proxy = self.iwd._proxy + proxy.InterfacesAdded.connect(self.on_device_add) + proxy.InterfacesRemoved.connect(self.on_device_remove) def start(self): """ start the daemon """ + logger.debug("Starting daemon") + self.loop.run() diff --git a/naxalnet/iwd.py b/naxalnet/iwd.py index 19b87b5..ea58643 100644 --- a/naxalnet/iwd.py +++ b/naxalnet/iwd.py @@ -59,7 +59,6 @@ and what they mean: import logging from dasbus.connection import SystemMessageBus -# from naxalnet.log import logger logger = logging.getLogger(__name__) IWD_BUS = "net.connman.iwd" diff --git a/naxalnet/scripts.py b/naxalnet/scripts.py index 99ae572..60242a8 100644 --- a/naxalnet/scripts.py +++ b/naxalnet/scripts.py @@ -32,13 +32,16 @@ from pathlib import Path from shutil import copy from dasbus.error import DBusError from systemd import journal +from systemd.daemon import notify from naxalnet import __version__ from naxalnet.iwd import Adapter, Device, IWD from naxalnet.config import parse_args +from naxalnet.daemon import Daemon -# from naxalnet.log import logger - -logger = logging.getLogger(__name__) +# Do not use getLogger(__name__) here. +# getLogger() without any args will give us +# the root logger, which is waht we need. +logger = logging.getLogger() args = parse_args() @@ -50,6 +53,7 @@ def copy_files(): See man:systemd.network(5) """ try: + notify("STATUS=Configuring the network...") logger.info("Copying network config files") dest = Path(args.networkd_runtime_dir) src = Path(args.networkd_config_dir) @@ -72,6 +76,7 @@ def setup_devices(): is connected or removed. """ try: + notify("STATUS=Setting up mesh...") iwd = IWD() devices = iwd.get_devices() adhoc_devices = [] @@ -122,11 +127,12 @@ def setup_devices(): ap_adapter.power_on() ap_device.start_ap(args.ap_ssid, args.ap_passwd) else: - logger.info("Not setting up WiFi AP.") + logger.warning("Not setting up WiFi AP.") else: logger.warning( "No device found to setup mesh. Make sure a WiFi adapter is connected" ) + except DBusError: logger.exception("Error while communicating with iwd") sys.exit(4) @@ -170,7 +176,7 @@ def main(): # if --systemd is given, log to systemd journal if args.systemd: - logger.setLevel(level=logging.DEBUG) + logging.basicConfig(level=logging.DEBUG) logger.addHandler(journal.JournalHandler()) else: logging.basicConfig(level=loglevel) @@ -178,6 +184,17 @@ def main(): copy_files() setup_devices() + # Notify systemd that naxalnet is ready. + # see man:sd_notify(3) + notify("READY=1") - # naxalnet prints Bye if no errors occured + # Start the daemon so that setup_devices() is called every + # time a device is connected or removed. + daemon = Daemon() + daemon.add_callback(setup_devices) + + notify("STATUS=Waiting for changes") + daemon.start() + + # naxalnet prints Bye while exiting. logger.info("Bye") From ca1e721c9ee3e9d0daa3dcabc7e8d7a0a4a72ddc Mon Sep 17 00:00:00 2001 From: Pranav Jerry Date: Tue, 7 Sep 2021 18:45:11 +0530 Subject: [PATCH 06/10] fixed logging issue and another bug There was a problem with indentation which made the line starting adhoc not being run at all. Updated CHANGELOG Moved some things to other places log.py is back! It isn't needed, but it doesn't do any harm anyway. --- CHANGELOG.md | 6 ++++-- README.md | 11 +++++------ naxalnet/__init__.py | 2 +- naxalnet/config.py | 3 +++ naxalnet/daemon.py | 4 +--- naxalnet/iwd.py | 10 ++++------ naxalnet/log.py | 38 ++++++++++++++++++++++++++++++++++++++ naxalnet/scripts.py | 41 ++++++++++------------------------------- 8 files changed, 66 insertions(+), 49 deletions(-) create mode 100644 naxalnet/log.py diff --git a/CHANGELOG.md b/CHANGELOG.md index c2538b5..03bbce2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,11 @@ # Changelog -## [Unreleased][] - 2021-09-06 +## [Unreleased][] - 2021-09-07 +- naxalnet is now a daemon! naxalnet will reconfigure the WiFi network + every time a WiFi adapter is plugged in or removed - **Logging**: logs to systemd journal when run from systemd, stderr - otherwise. + otherwise - New dependency `python3-systemd` - Fixed dependency order in systemd service - Added `--verbose` argument diff --git a/README.md b/README.md index 07151d4..2b2a3fd 100644 --- a/README.md +++ b/README.md @@ -18,13 +18,12 @@ network.