Commit 97aa574b authored by David Trattnig's avatar David Trattnig
Browse files

Monitoring for Engine startup.

parent 55835eda
......@@ -33,13 +33,19 @@ from_mail="monitoring@aura.engine"
# The beginning of the subject. With that you can easily apply filter rules using a mail client
mailsubject_prefix="[Aura Engine]"
[dataurls]
# The URL to get the Calendar via PV/Steering
api_calendar_url="http://localhost:8000/api/v1/playout"
# The URL to get show details via PV/Steering
api_show_url="http://localhost:8000/api/v1/shows/${ID}/"
[api]
# STEERING
api_steering_status = "http://localhost:8000/api/v1/playout"
# The URL to get the Calendar via Steering
api_steering_calendar="http://localhost:8000/api/v1/playout"
# The URL to get show details via Steering
api_steering_show="http://localhost:8000/api/v1/shows/${ID}/"
# TANK
api_tank_status = "http://localhost:8040/ui/"
# The URL to get playlist details via Tank
api_playlist_url="http://localhost:8040/api/v1/shows/${SLUG}/playlists"
api_tank_playlist="http://localhost:8040/api/v1/shows/${SLUG}/playlists"
# URL and Port of the API endpoints exposed by engine
exposed_api_url=http://localhost:3333/api/v1/
......@@ -121,13 +127,13 @@ soundsystem="alsa"
# with alsa you have to write the devicenames like hw:0
# with pulse and jack => an non empty value means it is used
# devices with empty string are ignored and not used
input_device_0=""
input_device_0="hw:0"
input_device_1=""
input_device_2=""
input_device_3=""
input_device_4=""
# same same, but different
output_device_0="default"
output_device_0="hw:0"
output_device_1=""
output_device_2=""
output_device_3=""
......
......@@ -33,13 +33,19 @@ from_mail="monitoring@aura.engine"
# The beginning of the subject. With that you can easily apply filter rules using a mail client
mailsubject_prefix="[Aura Engine]"
[dataurls]
# The URL to get the Calendar via PV/Steering
api_calendar_url="http://localhost:8000/api/v1/playout"
# The URL to get show details via PV/Steering
api_show_url="http://localhost:8000/api/v1/shows/${ID}/"
[api]
# STEERING
api_steering_status = "http://localhost:8000/api/v1/playout"
# The URL to get the Calendar via Steering
api_steering_calendar="http://localhost:8000/api/v1/playout"
# The URL to get show details via Steering
api_steering_show="http://localhost:8000/api/v1/shows/${ID}/"
# TANK
api_tank_status = "http://localhost:8040/ui/"
# The URL to get playlist details via Tank
api_playlist_url="http://localhost:8040/api/v1/shows/${SLUG}/playlists"
api_tank_playlist="http://localhost:8040/api/v1/shows/${SLUG}/playlists"
# URL and Port of the API endpoints exposed by engine
exposed_api_url=http://localhost:3333/api/v1/
......@@ -120,13 +126,13 @@ soundsystem="alsa"
# with alsa you have to write the devicenames like hw:0
# with pulse and jack => an non empty value means it is used
# devices with empty string are ignored and not used
input_device_0=""
input_device_0="hw:0"
input_device_1=""
input_device_2=""
input_device_3=""
input_device_4=""
# same same, but different
output_device_0="default"
output_device_0="hw:0"
output_device_1=""
output_device_2=""
output_device_3=""
......
......@@ -33,13 +33,19 @@ from_mail="monitoring@aura.engine"
# The beginning of the subject. With that you can easily apply filter rules using a mail client
mailsubject_prefix="[Aura Engine]"
[dataurls]
# The URL to get the Calendar via PV/Steering
api_calendar_url="http://localhost:8000/api/v1/playout"
# The URL to get show details via PV/Steering
api_show_url="http://localhost:8000/api/v1/shows/${ID}/"
[api]
# STEERING
api_steering_status = "http://localhost:8000/api/v1/playout"
# The URL to get the Calendar via Steering
api_steering_calendar="http://localhost:8000/api/v1/playout"
# The URL to get show details via Steering
api_steering_show="http://localhost:8000/api/v1/shows/${ID}/"
# TANK
api_tank_status = "http://localhost:8040/ui/"
# The URL to get playlist details via Tank
api_playlist_url="http://localhost:8040/api/v1/shows/${SLUG}/playlists"
api_tank_playlist="http://localhost:8040/api/v1/shows/${SLUG}/playlists"
# URL and Port of the API endpoints exposed by engine
exposed_api_url=http://localhost:3333/api/v1/
......@@ -120,13 +126,13 @@ soundsystem="alsa"
# with alsa you have to write the devicenames like hw:0
# with pulse and jack => an non empty value means it is used
# devices with empty string are ignored and not used
input_device_0=""
input_device_0="hw:0"
input_device_1=""
input_device_2=""
input_device_3=""
input_device_4=""
# same same, but different
output_device_0="default"
output_device_0="hw:0"
output_device_1=""
output_device_2=""
output_device_3=""
......
......@@ -112,7 +112,7 @@ Configure monitoring parameters such as admin emails in the `[monitoring]` secti
## API Endpoints
Configure connections to the other Aura components in the `[dataurls]` section.
Configure connections to the other Aura components in the `[api]` section.
Sets the API URL exposed to external clients. This is required by the included
web applications which access the API.
......
......@@ -44,17 +44,21 @@ using a fancy calendar interface.
These data-sources need to be configurated in the "engine.ini" configuration file:
# STEERING
api_steering_status = "http://localhost:8000/api/v1/"
# The URL to get the Calendar via Steering
api_calendar_url="http://localhost:8000/api/v1/playout"
api_steering_calendar="http://localhost:8000/api/v1/playout"
# The URL to get show details via Steering
api_show_url="http://localhost:8000/api/v1/shows/${ID}/"
api_steering_show="http://localhost:8000/api/v1/shows/${ID}/"
The AURA Project "**Tank**" on the other hand delivers information on the tracks, related playlists
to be played and its meta-data:
# TANK
api_tank_status = "http://localhost:8040/ui/"
# The URL to get playlist details via Tank
api_playlist_url="http://localhost:8040/api/v1/shows/${SLUG}/playlists"
api_tank_playlist="http://localhost:8040/api/v1/shows/${SLUG}/playlists"
More information you can find here: <https://gitlab.servus.at/autoradio/meta/blob/master/api-definition.md>
......
......@@ -124,13 +124,17 @@ Now, specify at least following settings to get started:
Set the URLs to the *Steering* and *Tank* API:
```ini
[dataurls]
# The URL to get the Calendar via PV/Steering
api_calendar_url="http://localhost:8000/api/v1/playout"
# The URL to get show details via PV/Steering
api_show_url="http://localhost:8000/api/v1/shows/${ID}/"
# The URL to get playlist details via Tank
api_playlist_url="http://localhost:8040/api/v1/shows/${SLUG}/playlists"
# STEERING
api_steering_status = "http://localhost:8000/api/v1/"
# The URL to get the Calendar via Steering
api_steering_calendar="http://localhost:8000/api/v1/playout"
# The URL to get show details via Steering
api_steering_show="http://localhost:8000/api/v1/shows/${ID}/"
# TANK
api_tank_status = "http://localhost:8040/ui/"
# The URL to get playlist details via Tank
api_tank_playlist="http://localhost:8040/api/v1/shows/${SLUG}/playlists"
```
Ensure that the Liquidsoap installation path is valid:
......
......@@ -175,13 +175,17 @@ Now, specify at least following settings to get started:
Set the URLs to the *Steering* and *Tank* API:
```ini
[dataurls]
# The URL to get the Calendar via Steering
api_calendar_url="https://aura-test.o94.at/steering/api/v1/playout"
# The URL to get show details via Steering
api_show_url="http://aura-test.o94.at/steering/api/v1/shows/${ID}/"
# The URL to get playlist details via Tank
api_playlist_url="http://aura-test.o94.at/tank/api/v1/shows/${SLUG}/playlists"
# STEERING
api_steering_status = "http://localhost:8000/api/v1/"
# The URL to get the Calendar via Steering
api_steering_calendar="http://localhost:8000/api/v1/playout"
# The URL to get show details via Steering
api_steering_show="http://localhost:8000/api/v1/shows/${ID}/"
# TANK
api_tank_status = "http://localhost:8040/ui/"
# The URL to get playlist details via Tank
api_tank_playlist="http://localhost:8040/api/v1/shows/${SLUG}/playlists"
```
Ensure that the Liquidsoap installation path is valid:
......
......@@ -123,7 +123,7 @@ class Guru():
self.parser.add_argument("-sd", "--shutdown", action="store_true", dest="shutdown", default=False, help="Shutting down aura server")
# playlist in/output
self.parser.add_argument("-fnp", "--fetch-new-programmes", action="store_true", dest="fetch_new_programme", default=False, help="Fetch new programmes from api_calendar_url in engine.ini")
self.parser.add_argument("-fnp", "--fetch-new-programmes", action="store_true", dest="fetch_new_programme", default=False, help="Fetch new programmes from api_steering_calendar in engine.ini")
self.parser.add_argument("-pmq", "--print-message-queue", action="store_true", dest="print_message_queue", default=False, help="Prints message queue")
# send a redis message
......
......@@ -3,8 +3,8 @@ __author__ = "David Trattnig and Gottfried Gaisbauer"
__copyright__ = "Copyright 2017-2020, Aura Engine Team"
__credits__ = ["David Trattnig", "Gottfried Gaisbauer", "Michael Liebler"]
__license__ = "GNU Affero General Public License (AGPL) Version 3"
__version__ = "0.6.3"
__version_info__ = (0, 6, 3)
__version__ = "0.6.4"
__version_info__ = (0, 6, 4)
__maintainer__ = "David Trattnig"
__email__ = "david.trattnig@subsquare.at"
__status__ = "Development"
\ No newline at end of file
......@@ -47,6 +47,9 @@ class NoActiveEntryException(Exception):
# Monitoring Exceptions
class EngineMalfunctionException(Exception):
pass
class MailingException(Exception):
pass
......
#
# Aura Engine
#
# Copyright (C) 2020 David Trattnig <david.trattnig@subsquare.at>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import urllib
import logging
import os.path
from os import path
from modules.communication.redis.adapter import ClientRedisAdapter
class Monitoring:
"""
Engine Monitoring
"""
logger = None
soundsystem = None
status = None
def __init__(self, config, soundsystem):
"""
Initialize Monitoring
"""
self.logger = logging.getLogger("AuraEngine")
self.config = config
self.soundsystem = soundsystem
self.status = dict()
self.status["soundsystem"] = dict()
def update_status(self):
"""
Requests the current status of all components
"""
self.status["soundsystem"]["mixer"] = self.soundsystem.get_mixer_status()
#self.status["soundsystem"]["recorder"] = self.soundsystem.get_recorder_status()
self.status["redis_ready"] = self.validate_redis_connection()
self.status["api_steering_ready"] = self.validate_url_connection(self.config.get("api_steering_status"))
self.status["api_tank_ready"] = self.validate_url_connection(self.config.get("api_tank_status"))
self.status["audio_store"] = self.validate_directory(self.config.get("audiofolder"))
# Set overall status
if self.has_valid_status():
self.status["engine_status"] = "OK"
else:
self.status["engine_status"] = "INVALID"
def get_status(self):
"""
Retrieves the current monitoring status.
"""
self.update_status()
return self.status
def has_valid_status(self):
"""
Checks if the current status is valid to run engine
"""
if self.status["soundsystem"]["mixer"]["in_filesystem_0"] \
and self.status["redis_ready"] \
and self.status["audio_store"]["exists"]:
return True
return False
def validate_url_connection(self, url):
"""
Checks if connection to passed URL is successful.
"""
try:
request = urllib.request.Request(url)
response = urllib.request.urlopen(request)
response.read()
except Exception:
return False
return True
def validate_redis_connection(self):
"""
Checks if the connection to Redis is successful.
"""
try:
cra = ClientRedisAdapter(self.config)
cra.publish("aura", "status")
except:
return False
return True
def validate_directory(self, dir_path):
"""
Checks if a given directory is existing and holds content
"""
status = dict()
status["exists"] = path.exists(dir_path) and os.path.isdir(dir_path)
status["has_content"] = False
if status["exists"]:
status["has_content"] = any([True for _ in os.scandir(dir_path)])
return status
\ No newline at end of file
......@@ -23,11 +23,12 @@ import logging
import datetime
import threading
import meta
import json
from modules.base.exceptions import NoActiveScheduleException
from modules.base.exceptions import NoActiveScheduleException, EngineMalfunctionException
from modules.base.enum import Channel, ChannelType
from modules.base.utils import TerminalColors, SimpleUtil, EngineUtil
from modules.core.monitor import Monitoring
class StartupThread(threading.Thread):
"""
......@@ -39,7 +40,7 @@ class StartupThread(threading.Thread):
active_entry = None
soundsystem = None
scheduler = None
monitoring = None
def __init__(self, soundsystem):
"""
......@@ -49,7 +50,7 @@ class StartupThread(threading.Thread):
self.logger = logging.getLogger("AuraEngine")
self.soundsystem = soundsystem
self.scheduler = soundsystem.scheduler
self.monitoring = Monitoring(soundsystem.config, soundsystem)
def run(self):
......@@ -58,6 +59,15 @@ class StartupThread(threading.Thread):
"""
try:
self.soundsystem.start()
status = self.monitoring.get_status()
self.logger.info("Status Monitor:\n%s" % json.dumps(status, indent=4))
if not status["engine_status"] == "OK":
self.logger.info("Engine Status: " + SimpleUtil.red(status["engine_status"]))
raise EngineMalfunctionException
else:
self.logger.info("Engine Status: " + SimpleUtil.green("OK"))
self.logger.info(EngineUtil.engine_info("Engine Core", meta.__version__))
self.scheduler.on_ready()
......
......@@ -34,10 +34,9 @@ class CalendarFetcher:
"""
self.config = config
self.logger = logging.getLogger("AuraEngine")
self.__set_url__("api_calendar_url")
self.__set_url__("api_playlist_url")
self.__set_url__("api_show_url")
self.__set_url__("api_steering_calendar")
self.__set_url__("api_tank_playlist")
self.__set_url__("api_steering_show")
#
# PUBLIC METHODS
......@@ -54,11 +53,11 @@ class CalendarFetcher:
self.logger.debug("Fetching schedules from STEERING")
self.fetched_schedule_data = self.__fetch_schedule_data__()
except urllib.error.HTTPError as e:
self.logger.critical("Cannot fetch from " + self.url["api_calendar_url"] + "! Reason: " + str(e))
self.logger.critical("Cannot fetch from " + self.url["api_steering_calendar"] + "! Reason: " + str(e))
self.fetched_schedule_data = None
return None
except (urllib.error.URLError, IOError, ValueError) as e:
self.logger.critical("Cannot connect to " + self.url["api_calendar_url"] + "! Reason: " + str(e))
self.logger.critical("Cannot connect to " + self.url["api_steering_calendar"] + "! Reason: " + str(e))
self.fetched_schedule_data = None
return None
......@@ -67,11 +66,11 @@ class CalendarFetcher:
self.logger.debug("Fetching playlists from TANK")
self.__fetch_schedule_playlists__()
except urllib.error.HTTPError as e:
self.logger.critical("Cannot fetch from " + self.url["api_playlist_url"] + "! Reason: " + str(e))
self.logger.critical("Cannot fetch from " + self.url["api_tank_playlist"] + "! Reason: " + str(e))
self.fetched_schedule_data = None
return None
except (urllib.error.URLError, IOError, ValueError) as e:
self.logger.critical("Cannot connect to " + self.url["api_playlist_url"] + "! Reason: " + str(e))
self.logger.critical("Cannot connect to " + self.url["api_tank_playlist"] + "! Reason: " + str(e))
self.fetched_schedule_data = None
return None
......@@ -129,7 +128,7 @@ class CalendarFetcher:
Returns:
([Schedule]): An array of schedules
"""
servicetype = "api_calendar_url"
servicetype = "api_steering_calendar"
schedule = None
# fetch data from steering
......@@ -193,7 +192,7 @@ class CalendarFetcher:
Returns:
(Schedule): The given schedule with additional show fields set.
"""
servicetype = "api_show_url"
servicetype = "api_steering_show"
url = self.__build_url__(servicetype, "${ID}", str(schedule["show_id"]))
json_response = self.__fetch_data__(servicetype, url)
......@@ -221,7 +220,7 @@ class CalendarFetcher:
Returns:
([Schedule]): Array of playlists
"""
servicetype = "api_playlist_url"
servicetype = "api_tank_playlist"
# fetch playlists from TANK
if not "show_slug" in schedule:
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment