Update for APRSD 3.0.0 release.

This provides the new config options defined in the plugin code
itself.
This commit is contained in:
Hemna 2022-12-29 08:49:01 -05:00
parent b624055d06
commit 63726e426e
11 changed files with 197 additions and 155 deletions

View File

@ -1,9 +1,12 @@
import logging
from oslo_config import cfg
from slack_sdk import WebClient
import aprsd_slack_plugin
CONF = cfg.CONF
LOG = logging.getLogger("APRSD")
@ -39,33 +42,29 @@ class SlackPluginBase:
"""
version = aprsd_slack_plugin.__version__
swc = None
slack_channels = None
def setup_slack(self):
"""Create the slack require client from config."""
# signing_secret = self.config["slack"]["signing_secret"]
try:
self.config.exists(["services", "slack", "bot_token"])
except Exception as ex:
LOG.error("Failed to find config slack:bot_token {}".format(ex))
return "No slack bot_token found"
if not CONF.aprsd_slack_plugin.signing_secret:
LOG.error("Failed to find config aprsd_slack_plugin.signing_secret")
return "No slack signing_secret found"
bot_token = self.config["services"]["slack"]["bot_token"]
if not bot_token:
if not CONF.aprsd_slack_plugin.bot_token:
LOG.error(
"APRSD config is missing slack: bot_token:<token>. "
"APRSD config is missing aprsd_slack_plugin.bot_token. "
"Please install the slack app and get the "
"Bot User OAth Access Token.",
)
return False
self.swc = WebClient(token=bot_token)
self.slack_channels = self.config["services"]["slack"].get("channels", None)
if not self.slack_channels:
LOG.error(
"APRSD config is missing slack: channels: <name> "
"Please add a slack channel name to send messages.",
)
if not CONF.aprsd_slack_plugin.channels:
LOG.error("aprsd_slack_plugin.channels is missing")
return False
self.swc = WebClient(token=CONF.aprsd_slack_plugin.bot_token)
self.slack_channels = CONF.aprsd_slack_plugin.channels
return True

View File

@ -0,0 +1,10 @@
import logging
from oslo_config import cfg
from aprsd_slack_plugin.conf import slack
CONF = cfg.CONF
slack.register_opts(CONF)

View File

@ -0,0 +1,80 @@
# Copyright 2015 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
This is the single point of entry to generate the sample configuration
file for Nova. It collects all the necessary info from the other modules
in this package. It is assumed that:
* every other module in this package has a 'list_opts' function which
return a dict where
* the keys are strings which are the group names
* the value of each key is a list of config options for that group
* the nova.conf package doesn't have further packages with config options
* this module is only used in the context of sample file generation
"""
import collections
import importlib
import os
import pkgutil
LIST_OPTS_FUNC_NAME = "list_opts"
def _tupleize(dct):
"""Take the dict of options and convert to the 2-tuple format."""
return [(key, val) for key, val in dct.items()]
def list_opts():
opts = collections.defaultdict(list)
module_names = _list_module_names()
imported_modules = _import_modules(module_names)
_append_config_options(imported_modules, opts)
return _tupleize(opts)
def _list_module_names():
module_names = []
package_path = os.path.dirname(os.path.abspath(__file__))
for _, modname, ispkg in pkgutil.iter_modules(path=[package_path]):
if modname == "opts" or ispkg:
continue
else:
module_names.append(modname)
return module_names
def _import_modules(module_names):
imported_modules = []
for modname in module_names:
mod = importlib.import_module("aprsd_slack_plugin.conf." + modname)
if not hasattr(mod, LIST_OPTS_FUNC_NAME):
msg = "The module 'aprsd_slack_plugin.conf.%s' should have a '%s' "\
"function which returns the config options." % \
(modname, LIST_OPTS_FUNC_NAME)
raise Exception(msg)
else:
imported_modules.append(mod)
return imported_modules
def _append_config_options(imported_modules, config_options):
for mod in imported_modules:
configs = mod.list_opts()
for key, val in configs.items():
config_options[key].extend(val)

View File

@ -0,0 +1,43 @@
from oslo_config import cfg
slack_group = cfg.OptGroup(
name="aprsd_slack_plugin",
title="APRSD Slack Plugin settings",
)
slack_opts = [
cfg.StrOpt(
"signing_secret",
default=None,
help="Your Slack account signing secret"
"You have to create a slack bot account first. "
"https://api.slack.com/start/building/bolt-python",
),
cfg.StrOpt(
"bot_token",
default=None,
help="Your Slack bot's token",
),
cfg.ListOpt(
"channels",
default=None,
help="The channels you want messages sent to. This is a CSV list"
"of slack channel names.",
),
]
ALL_OPTS = (
slack_opts
)
def register_opts(cfg):
cfg.register_group(slack_group)
cfg.register_opts(ALL_OPTS, group=slack_group)
def list_opts():
return {
slack_group.name: slack_opts,
}

View File

@ -3,15 +3,21 @@ import re
import time
from aprsd import packets, plugin, plugin_utils
from oslo_config import cfg
import aprsd_slack_plugin
from aprsd_slack_plugin import base_plugin
CONF = cfg.CONF
LOG = logging.getLogger("APRSD")
class SlackLocationPlugin(base_plugin.SlackPluginBase, plugin.APRSDRegexCommandPluginBase):
class SlackLocationPlugin(
base_plugin.SlackPluginBase,
plugin.APRSDRegexCommandPluginBase,
plugin.APRSFIKEYMixin,
):
"""SlackCommandPlugin.
This APRSD plugin looks for the location command comming in
@ -35,7 +41,7 @@ class SlackLocationPlugin(base_plugin.SlackPluginBase, plugin.APRSDRegexCommandP
Install the app/bot into your workspace.
Edit your ~/.config/aprsd/aprsd.yml and add the section
Edit your ~/.config/aprsd/aprsd.conf and add the section
slack:
signing_secret: <signing secret token here>
bot_token: <Bot User OAuth Access Token here>
@ -48,24 +54,21 @@ class SlackLocationPlugin(base_plugin.SlackPluginBase, plugin.APRSDRegexCommandP
command_regex = "^[lL]"
command_name = "location-slack"
def setup(self):
self.ensure_aprs_fi_key()
if self.enabled:
config_set = self.setup_slack()
if not config_set:
self.enabled = False
def process(self, packet):
LOG.info("SlackCommandPlugin")
fromcall = packet.from_call
message = packet.message_text
is_setup = self.setup_slack()
if not is_setup:
return
# get last location of a callsign, get descriptive name from weather service
try:
self.config.exists(["services", "aprs.fi", "apiKey"])
except Exception as ex:
LOG.error(f"Failed to find config aprs.fi:apikey {ex}")
return "No aprs.fi apikey found"
api_key = self.config["services"]["aprs.fi"]["apiKey"]
api_key = CONF.aprs_fi.apiKey
# optional second argument is a callsign to search
a = re.search(r"^.*\s+(.*)", message)

View File

@ -2,11 +2,13 @@ import logging
import re
from aprsd import packets
from oslo_config import cfg
import aprsd_slack_plugin
from aprsd_slack_plugin import base_plugin
CONF = cfg.CONF
LOG = logging.getLogger("APRSD")
@ -46,19 +48,20 @@ class SlackMessagePlugin(base_plugin.SlackPluginBase):
command_regex = "^[sS]"
command_name = "message-slack"
def setup(self):
config_set = self.setup_slack()
if not config_set:
self.enabled = False
else:
self.enabled = True
def command(self, packet):
message = packet.message_text
fromcall = packet.from_call
LOG.info(f"SlackMessagePlugin '{message}'")
is_setup = self.setup_slack()
if not is_setup:
LOG.error("Slack isn't setup!")
return
# optional second argument is a callsign to search
a = re.search(r"^.*\s+(.*)", message)
LOG.debug(a)
if a is not None:
searchcall = a.group(1)
searchcall = searchcall.upper()

View File

@ -1,10 +1,13 @@
import logging
from aprsd import messaging, packets, plugin
from oslo_config import cfg
import aprsd_slack_plugin
from aprsd_slack_plugin import base_plugin
CONF = cfg.CONF
LOG = logging.getLogger("APRSD")
@ -16,10 +19,17 @@ class SlackNotifyPlugin(
version = aprsd_slack_plugin.__version__
def setup(self):
config_set = self.setup_slack()
if not config_set:
self.enabled = False
else:
self.enabled = True
def process(self, packet):
LOG.info("SlackCommandPlugin")
fromcall = packet["from"]
fromcall = packet.from_call
# message = packet["message_text"]
is_setup = self.setup_slack()
@ -29,13 +39,13 @@ class SlackNotifyPlugin(
wl = packets.WatchList()
if wl.is_old(packet["from"]):
# get last location of a callsign, get descriptive name from weather service
callsign_url = "<http://aprs.fi/info/a/{}|{}>".format(fromcall, fromcall)
callsign_url = f"<http://aprs.fi/info/a/{fromcall}|{fromcall}>"
message = {}
message["username"] = "APRSD - Slack Notification Plugin"
message["icon_emoji"] = ":satellite_antenna:"
message["attachments"] = [{}]
message["text"] = "{} - Is now on APRS".format(callsign_url)
message["text"] = f"{callsign_url} - Is now on APRS"
message["channel"] = "#hemna"
LOG.debug(message)

View File

@ -1,111 +0,0 @@
#
# This file is autogenerated by pip-compile with Python 3.9
# by the following command:
#
# pip-compile --annotation-style=line --resolver=backtracking requirements-dev.in
#
alabaster==0.7.12 # via sphinx
aprsd==2.6.1 # via -r requirements-dev.in
aprslib==0.7.2 # via aprsd
attrs==22.1.0 # via aprsd, ax253, kiss3, pytest
ax253==0.1.5.post1 # via aprsd, kiss3
babel==2.11.0 # via sphinx
beautifulsoup4==4.11.1 # via aprsd
bidict==0.22.0 # via aprsd, python-socketio
bitarray==2.6.0 # via aprsd, ax253, kiss3
black==22.12.0 # via -r requirements-dev.in
build==0.9.0 # via pip-tools
cachetools==5.2.0 # via tox
certifi==2022.12.7 # via aprsd, requests
cffi==1.15.1 # via aprsd, cryptography
cfgv==3.3.1 # via pre-commit
chardet==5.1.0 # via tox
charset-normalizer==2.1.1 # via aprsd, requests
click==8.1.3 # via aprsd, black, click-completion, flask, pip-tools
click-completion==0.5.2 # via aprsd
colorama==0.4.6 # via tox
commonmark==0.9.1 # via aprsd, rich
coverage[toml]==6.5.0 # via pytest-cov
cryptography==38.0.4 # via aprsd, pyopenssl
distlib==0.3.6 # via virtualenv
dnspython==2.2.1 # via aprsd, eventlet
docutils==0.19 # via sphinx
eventlet==0.33.2 # via aprsd
exceptiongroup==1.0.4 # via pytest
filelock==3.8.2 # via tox, virtualenv
flake8==6.0.0 # via -r requirements-dev.in, pep8-naming
flask==2.1.2 # via aprsd, flask-classful, flask-httpauth, flask-socketio
flask-classful==0.14.2 # via aprsd
flask-httpauth==4.7.0 # via aprsd
flask-socketio==5.3.2 # via aprsd
greenlet==2.0.1 # via aprsd, eventlet
identify==2.5.10 # via pre-commit
idna==3.4 # via aprsd, requests
imagesize==1.4.1 # via sphinx
imapclient==2.3.1 # via aprsd
importlib-metadata==5.1.0 # via aprsd, ax253, flask, kiss3, sphinx
iniconfig==1.1.1 # via pytest
isort==5.11.3 # via -r requirements-dev.in
itsdangerous==2.1.2 # via aprsd, flask
jinja2==3.1.2 # via aprsd, click-completion, flask, sphinx
kiss3==8.0.0 # via aprsd
markupsafe==2.1.1 # via aprsd, jinja2
mccabe==0.7.0 # via flake8
mypy==0.991 # via -r requirements-dev.in
mypy-extensions==0.4.3 # via black, mypy
nodeenv==1.7.0 # via pre-commit
packaging==22.0 # via build, pyproject-api, pytest, sphinx, tox
pathspec==0.10.3 # via black
pbr==5.11.0 # via -r requirements-dev.in, aprsd
pep517==0.13.0 # via build
pep8-naming==0.13.2 # via -r requirements-dev.in
pip-tools==6.12.1 # via -r requirements-dev.in
platformdirs==2.6.0 # via black, tox, virtualenv
pluggy==1.0.0 # via aprsd, pytest, tox
pre-commit==2.20.0 # via -r requirements-dev.in
pycodestyle==2.10.0 # via flake8
pycparser==2.21 # via aprsd, cffi
pyflakes==3.0.1 # via flake8
pygments==2.13.0 # via aprsd, rich, sphinx
pyopenssl==22.1.0 # via aprsd
pyproject-api==1.2.1 # via tox
pyserial==3.5 # via aprsd, pyserial-asyncio
pyserial-asyncio==0.6 # via aprsd, kiss3
pytest==7.2.0 # via -r requirements-dev.in, pytest-cov
pytest-cov==4.0.0 # via -r requirements-dev.in
python-engineio==4.3.4 # via aprsd, python-socketio
python-socketio==5.7.2 # via aprsd, flask-socketio
pytz==2022.6 # via aprsd, babel
pyyaml==6.0 # via aprsd, pre-commit
requests==2.28.1 # via aprsd, sphinx, update-checker
rich==12.6.0 # via aprsd
shellingham==1.5.0 # via aprsd, click-completion
six==1.16.0 # via aprsd, click-completion, eventlet, imapclient
snowballstemmer==2.2.0 # via sphinx
soupsieve==2.3.2.post1 # via aprsd, beautifulsoup4
sphinx==5.3.0 # via -r requirements-dev.in
sphinxcontrib-applehelp==1.0.2 # via sphinx
sphinxcontrib-devhelp==1.0.2 # via sphinx
sphinxcontrib-htmlhelp==2.0.0 # via sphinx
sphinxcontrib-jsmath==1.0.1 # via sphinx
sphinxcontrib-qthelp==1.0.3 # via sphinx
sphinxcontrib-serializinghtml==1.1.5 # via sphinx
tabulate==0.9.0 # via aprsd
thesmuggler==1.0.1 # via aprsd
toml==0.10.2 # via pre-commit
tomli==2.0.1 # via black, build, coverage, mypy, pep517, pyproject-api, pytest, tox
tox==4.0.14 # via -r requirements-dev.in
typing-extensions==4.4.0 # via black, mypy
ua-parser==0.16.1 # via aprsd, user-agents
update-checker==0.18.0 # via aprsd
urllib3==1.26.13 # via aprsd, requests
user-agents==2.2.0 # via aprsd
virtualenv==20.17.1 # via pre-commit, tox
werkzeug==2.1.2 # via aprsd, flask
wheel==0.38.4 # via pip-tools
wrapt==1.14.1 # via aprsd
zipp==3.11.0 # via aprsd, importlib-metadata
# The following packages are considered to be unsafe in a requirements file:
# pip
# setuptools

View File

@ -1,4 +1,5 @@
pbr
slack_sdk>=3.0
slackeventsapi>=2.1.0
aprsd>=2.7.0
aprsd>=3.0.0
oslo_config

View File

@ -4,13 +4,13 @@
#
# pip-compile --annotation-style=line --resolver=backtracking requirements.in
#
aprsd==2.6.1 # via -r requirements.in
aprsd==3.0.0 # via -r requirements.in
aprslib==0.7.2 # via aprsd
attrs==22.1.0 # via aprsd, ax253, kiss3
attrs==22.2.0 # via aprsd, ax253, kiss3
ax253==0.1.5.post1 # via aprsd, kiss3
beautifulsoup4==4.11.1 # via aprsd
bidict==0.22.0 # via aprsd, python-socketio
bitarray==2.6.0 # via aprsd, ax253, kiss3
bitarray==2.6.1 # via aprsd, ax253, kiss3
certifi==2022.12.7 # via aprsd, requests
cffi==1.15.1 # via aprsd, cryptography
charset-normalizer==2.1.1 # via aprsd, requests
@ -27,7 +27,7 @@ flask-socketio==5.3.2 # via aprsd
greenlet==2.0.1 # via aprsd, eventlet
idna==3.4 # via aprsd, requests
imapclient==2.3.1 # via aprsd
importlib-metadata==5.1.0 # via aprsd, ax253, flask, kiss3
importlib-metadata==5.2.0 # via aprsd, ax253, flask, kiss3
itsdangerous==2.1.2 # via aprsd, flask
jinja2==3.1.2 # via aprsd, click-completion, flask
kiss3==8.0.0 # via aprsd
@ -42,7 +42,7 @@ pyserial==3.5 # via aprsd, pyserial-asyncio
pyserial-asyncio==0.6 # via aprsd, kiss3
python-engineio==4.3.4 # via aprsd, python-socketio
python-socketio==5.7.2 # via aprsd, flask-socketio
pytz==2022.6 # via aprsd
pytz==2022.7 # via aprsd
pyyaml==6.0 # via aprsd
requests==2.28.1 # via aprsd, update-checker
rich==12.6.0 # via aprsd

View File

@ -17,6 +17,10 @@ description_file =
README.rst
summary = Amateur radio APRS daemon which listens for messages and responds
[options.entry_points]
oslo.config.opts =
aprsd_slack_plugin.conf = aprsd_slack_plugin.conf.opts:list_opts
[global]
setup-hooks =
pbr.hooks.setup_hook