Merge pull request 'Convert into daemon' (#17) from daemon into master

Reviewed-on: pranav/naxalnet#17
This commit is contained in:
Pranav Jerry 2021-09-10 14:59:01 +00:00
commit 74a061507f
16 changed files with 321 additions and 163 deletions

View File

@ -1,9 +1,14 @@
# Changelog
## [Unreleased][] - 2021-09-05
## [Unreleased][] - 2021-09-09
- Now logs to systemd journal. New dependency - `python3-systemd`
- 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
- New dependency `python-systemd`
- Fixed dependency order in systemd service
- Added `--verbose` argument
## [v0.3.0][] - 2021-08-19
@ -22,9 +27,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

View File

@ -16,7 +16,7 @@ install: build
uninstall:
$(PIP) uninstall -y naxalnet
rm -rf /usr/share/naxalnet /usr/lib/systemd/system/naxalnet.service
@-test -d /etc/naxalnet && echo "The directory /etc/naxalnet was not removed." && \
@echo "The directory /etc/naxalnet was not removed." && \
echo "Do 'sudo make purge' to remove it."
# remove config files, like apt purge

View File

@ -18,13 +18,12 @@ network.
<!-- NOTE TO ACTIVISTS
Running this program in the world's largest (partly-free) democracy
may result in you getting arrested under the UAPA, and not
getting bail because of false evidence planted in your phone by
may result in you getting arrested under the Act Which Must Not Be Named,
and not getting bail because of false evidence planted in your phone by
Pegasus, or by a forensic lab in Gujarat.
The author, much like the Government of India, does not wish
to take responsibility in your well-being if you get arrested under
a draconian national security law.
The author, much like the GoI, does not wish to take responsibility in your
well-being if you get arrested under a draconian national security law.
-->
<!-- UNCOMMENT WHEN NECESSARY
@ -32,7 +31,7 @@ a draconian national security law.
**Disclaimer**:
In case you are either 1) a complete idiot; or 2) a member of the saffron
brigade; or 3) both, please be aware that this project is not affiliated
with any groups designated as "terrorist" groups in India.
with any human rights groups designated as "terrorist" groups in India.
Using the name naxal does not imply any form of connection
with anyone currently at risk of death in overcrowded prisons.
@ -46,12 +45,12 @@ with anyone currently at risk of death in overcrowded prisons.
- [iwd][] for controlling the WiFi adapter
- python3
- python3-setuptools, for building and installing naxalnet
- python3-systemd, for logging to systemd journal
- [python-systemd][], for logging to systemd journal
- [dasbus][], for communicating with iwd
- two or more machines with a WiFi adapter having ad-hoc support, called
- two or more machines with a WiFi adapter having ibss support, called
nodes or peers
- batctl (optional, for debugging)
- python3-pip (optional, for `make uninstall` to work)
- python3-pip (for installing dasbus on Debian-based distributions)
## Installing
@ -117,15 +116,10 @@ git clone https://git.disroot.org/pranav/naxalnet.git
cd naxalnet
```
Or, if you have an [IPFS client][ipfs] running, try this instead:
```sh
git clone http://k51qzi5uqu5dlye74be0n9iihwk6sm54vexo7bf7pdr4w811y6mmrcp25djozv.ipns.localhost:8080/naxalnet.git
```
Now, install naxalnet:
Now, build and install naxalnet:
```sh
make
sudo make install
```
@ -136,13 +130,24 @@ service files:
sudo systemctl daemon-reload
```
To upgrade, clean the build files, update the repo and reinstall:
```sh
make clean
git pull
make
sudo make uninstall install
```
This will keep the configuration files.
## How to use
You need more than one machine running naxalnet for the connection to work.
### Start naxalnet
Though naxalnet can run from the commandline, it was designed to be
Though naxalnet can run from the command line, it was designed to be
run as a systemd service.
To start naxalnet, do the command on all the nodes:
@ -152,25 +157,25 @@ sudo systemctl start naxalnet.service
This will start a mesh network and connect to all nodes.
To test if it works, run `sudo batctl n -w` and check for
nodes. If there are any nodes, your network is up.
nodes. If there are any nodes, your network is up. Press
Ctrl+C to stop `batctl`.
### Getting internet access
Connect an ethernet cable from a router to any of the peers and
[start naxalnet][startnx]. If it was already started, you should
Connect an ethernet cable from a router to any of the nodes and
renew the DHCP connection of all peers. To do this, type
`sudo networkctl renew bridge0` on all peers.
`sudo networkctl renew bridge0` on all nodes.
### Tethering via WiFi AP
If there are two adapters in a peer, naxalnet will start a
WiFi ap (also called WiFi hotspot) on one of them.
Connect two WiFi adapters on a device and [start naxalnet][startnx].
Now an ap will be started on one of the adapters.
Connect two WiFi adapters on a node.
Now an AP will be started on one of the adapters.
Type `naxalnet --print-wifi` to get the WiFi SSID and password.
If you had set up internet access on one of the peers, internet
If you had set up internet access on one of the nodes, internet
can be accessed from the AP.
### Running at boot
@ -223,7 +228,7 @@ naxalnet --help
## How it works
There are three modes commonly supported by WiFi adapters - `ap` (WiFi
hotspot), `station` (for joining WiFi networks) and `ad-hoc` (for
hotspot), `station` (for joining WiFi networks) and `ad-hoc` (or ibss, for
decentralised networks). There are other modes supported by some WiFi
adapters too, like `p2p` (WiFi direct), but this program doesn't use them.
@ -235,7 +240,7 @@ naxalnet starts an ad-hoc on one of them and an ap on the other.
You can use the ap for connecting mobile phones and other devices
to the mesh network.
Read the code and the documentation to learn the details.
Read the code and the documentation in the code to learn the details.
See the directory [systemd-networkd](systemd-networkd) to see how
systemd-networkd configures the network.
@ -284,13 +289,13 @@ See [HACKING.md](HACKING.md)
Many projects make setting up B.A.T.M.A.N. Advanced mesh networks with
WiFi routers easier. They are easier to setup and are more
configurable. But naxalnet is different from them. It simplifies
setting up mesh networks with _laptops or computers_, and is not
designed to work with routers.
setting up mesh networks with _laptops or computers_, and was not
made to work with routers.
The following projects does something similar to naxalnet, but
requires special devices or routers to work. If you live in an area
where the materials required for any of them are easily available,
consider using them instead of naxalnet.
where the materials are easily available, consider using them instead
of naxalnet.
- [LibreMesh][]: framework for OpenWrt-based firmwares
- [disaster.radio][]: solar-powered communications network
@ -322,3 +327,4 @@ See [LICENSE](LICENSE) for the complete version of the license.
[enablenx]: #running-at-boot
[requirements]: #requirements
[install-manual]: #manually
[python-systemd]: https://github.com/systemd/python-systemd

View File

@ -18,5 +18,6 @@ name = NxMesh
[ap]
# An AP is started if your machine has more than one WiFi adapter.
ssid = MeshWiFi
# Note the spelling. It's passwd, not password.
passwd = naxalnet256

View File

@ -17,28 +17,24 @@ 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
# Reload systemd-networkd after naxalnet exits
ExecStart=/usr/bin/naxalnet --systemd
# Reload systemd-networkd after naxalnet signals it is ready
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.*"
# Delete the interfaces created...
# When naxalnet exits, delete all files starting
# with mesh.* in /run/systemd/network
ExecStopPost=/usr/bin/find /run/systemd/network -type f -delete -name "mesh.*"
# Then delete the two 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

View File

@ -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"
__version__ = "0.3.0a3"

View File

@ -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 <http://www.gnu.org/licenses/>.
"""
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()

View File

@ -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 <http://www.gnu.org/licenses/>.
"""
config.py
@ -46,7 +60,6 @@ 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
def get_config_files():
@ -70,14 +83,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
@ -138,6 +151,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,
@ -145,5 +165,12 @@ def parse_args() -> Namespace:
help="prints the version and exit",
)
logger.debug("Parsing arguments")
parser.add_argument(
"-v", "--verbose", action="count", default=0, help="increase output verbosity"
)
# logger.debug("Parsing arguments")
return parser.parse_args()
args = parse_args()

69
naxalnet/daemon.py Normal file
View File

@ -0,0 +1,69 @@
# 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 <http://www.gnu.org/licenses/>.
"""
daemon.py
---------
The daemon part. This is currently under construction.
"""
from dasbus.loop import EventLoop
from naxalnet.iwd import IWD, IWD_DEVICE_INTERFACE
from naxalnet.log import logger
class Daemon:
"""implements the daemon part"""
def __init__(self):
self.loop = EventLoop()
self.iwd = IWD()
def on_device_add(self, path, data):
"""
this function will be run every time a device is added
"""
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, path, data):
"""
this function will be run every time a device is removed
"""
if IWD_DEVICE_INTERFACE in data:
logger.debug("A device was removed")
logger.info("Reloading")
self.callback()
def add_callback(self, callback):
"""
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()

View File

@ -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 <http://www.gnu.org/licenses/>.
"""
default.py

View File

@ -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 <http://www.gnu.org/licenses/>.
"""
iwd.py
------
@ -58,6 +56,7 @@ and what they mean:
- node: a machine that runs naxalnet and is therefore
connected to the mesh.
"""
from dasbus.connection import SystemMessageBus
from naxalnet.log import logger
@ -236,6 +235,7 @@ class Device:
if it isn't already on ad-hoc and power onn the device
if it is off
"""
print("Starting adhoc", name)
if self.get_mode() != "ad-hoc":
self.set_mode("ad-hoc")
@ -270,9 +270,7 @@ class Device:
# Stop ap if already started
self.stop_ap()
logger.debug(
"Starting ap on %s with ssid %s and password %s", self.name, ssid, passwd
)
logger.debug("Starting ap on %s with ssid %s", self.name, ssid)
self._proxy.Start(ssid, passwd)
def stop_ap(self):
@ -310,11 +308,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:
"""

View File

@ -1,16 +1,38 @@
#!/usr/bin/env python3
"""
log.py
------
This file contains the logger object, which is required for logging
to the systemd journal
Initialise the logger for other submodules to import. Do not
import any submodules here except for naxallnet.config
"""
import logging
from systemd import journal
from systemd.journal import JournalHandler
from naxalnet.config import args
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logger.addHandler(journal.JournalHandler())
def get_logger():
"""
Initialise the logger and return it.
This function is meant to be used only by naxalnet.log.
If you want to import the logger, use:
from naxalnet.log import logger
"""
log = logging.getLogger("naxalnet")
# --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:
logging.basicConfig(level=logging.DEBUG)
log.addHandler(JournalHandler())
else:
logging.basicConfig(level=loglevel)
return log
logger = get_logger()

View File

@ -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,103 +23,116 @@ 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
from pathlib import Path
from shutil import copy
from dasbus.error import DBusError
from systemd.daemon import notify
from naxalnet import __version__
from naxalnet.iwd import Adapter, Device, IWD
from naxalnet.config import parse_args
from naxalnet.log import logger
from naxalnet.iwd import Adapter, Device, IWD
from naxalnet.config import args
from naxalnet.daemon import Daemon
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:
notify("STATUS=Configuring the network...")
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:
notify("STATUS=Setting up mesh...")
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)
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.reload()
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_adapter.reload()
ap_device.start_ap(args.ap_ssid, args.ap_passwd)
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()
logger.info("Starting mesh on %s", adhoc_device.name)
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.warning("Not setting up WiFi AP.")
else:
logger.warning(
"No device found to setup mesh. Make sure a WiFi adapter is connected"
)
# naxalnet prints Bye if no errors occured
logger.info("Bye")
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
@ -135,31 +147,33 @@ 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(args)
print_wifi()
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()
# Notify systemd that naxalnet is ready.
# see man:sd_notify(3)
notify("READY=1")
try:
setup_devices(args)
except DBusError:
logger.exception("Error while communicating with iwd")
sys.exit(4)
# Start the daemon so that setup_devices() is called every
# time a device is connected or removed.
daemon = Daemon()
daemon.add_callback(setup_devices)
logger.debug("Finished.")
notify("STATUS=Waiting for changes")
daemon.start()
# naxalnet prints Bye while exiting.
logger.info("Bye")

3
pyproject.toml Normal file
View File

@ -0,0 +1,3 @@
[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"

View File

@ -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 =

View File

@ -1,5 +1,7 @@
#!/usr/bin/env python3
"""
See setup.py --help for usage
"""
from setuptools import setup
setup()