diff --git a/.dockerignore b/.dockerignore index 51bd219f82a5bc8ff8c5273fceb352697c26aad0..a3faf99806bbae64e341328e935bd35596691e5c 100644 --- a/.dockerignore +++ b/.dockerignore @@ -77,7 +77,7 @@ python .noseids # Configurations -config/engine.docker.ini +config/engine.docker.yaml env.list # Socket diff --git a/.gitignore b/.gitignore index 2bb85a609a5dacda35c3c8d062a5448cce2bdcf8..6f08aff2c316636c01ddb65e308b6b6b185e4ea5 100644 --- a/.gitignore +++ b/.gitignore @@ -13,10 +13,10 @@ docker.env /.cache /.build /.bash_history -/config/engine.ini +/config/engine.yaml /config/systemd/dev/ /audio -/config/docker.engine.ini -/config/engine.docker.ini +/config/docker.engine.yaml +/config/engine.docker.yaml .coverage coverage.xml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2333157867e10114dfb9307a8ec97df98aa2ffb4..4c9a67ee42db4b053470f09ec488ebd270503740 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -23,7 +23,7 @@ run_test_cases: stage: test before_script: - *install_requirements - - cp config/sample.engine.ini config/engine.ini + - cp config/sample.engine.yaml config/engine.yaml script: - make coverage coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/' diff --git a/Dockerfile b/Dockerfile index 79d396c86140664a418ac29ea71400873db2db0e..4aea77b5d2b5d355c4d11f62cfc6bfd557220119 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,7 +32,7 @@ WORKDIR /srv # Init Application COPY ./src/aura_engine /srv/src/aura_engine -COPY config/sample.engine.docker.ini /srv/config/engine.ini +COPY config/sample.engine.docker.yaml /srv/config/engine.yaml RUN poetry install --no-interaction --no-ansi # Update Permissions diff --git a/Makefile b/Makefile index affdadf62a326828ce9d02586e5609cc5ead538c..4561dde34d938a6218c1d5c55da3d44a13d82982 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ help:: TIMEZONE := "Europe/Vienna" AURA_ENGINE_CORE_SOCKET := "aura_engine_socket" -AURA_ENGINE_CONFIG := ${CURDIR}/config/engine.docker.ini +AURA_ENGINE_CONFIG := ${CURDIR}/config/engine.docker.yaml AURA_AUDIO_STORE_SOURCE := ${CURDIR}/../engine-core/audio/source AURA_AUDIO_STORE_PLAYLIST := ${CURDIR}/../engine-core/audio/playlist AURA_LOGS := ${CURDIR}/logs @@ -38,7 +38,7 @@ DOCKER_RUN = @docker run \ --mount type=tmpfs,destination=/tmp \ --env-file docker.env \ -v aura_engine_socket:"/srv/socket" \ - -v "$(AURA_ENGINE_CONFIG)":"/etc/aura/engine.ini":ro \ + -v "$(AURA_ENGINE_CONFIG)":"/etc/aura/engine.yaml":ro \ -v "$(AURA_AUDIO_STORE_SOURCE)":"/var/audio/source":ro \ -v "$(AURA_AUDIO_STORE_PLAYLIST)":"/var/audio/playlist":ro \ -v "$(AURA_LOGS)":"/srv/logs" \ @@ -50,14 +50,14 @@ DOCKER_RUN = @docker run \ init.app:: pyproject.toml poetry install - cp -n config/sample.engine.ini config/engine.ini + cp -n config/sample.engine.yaml config/engine.yaml mkdir -p .cache init.dev:: pyproject.toml poetry install --with dev poetry run pre-commit autoupdate poetry run pre-commit install - cp -n config/sample.engine.ini config/engine.ini + cp -n config/sample.engine.yaml config/engine.yaml mkdir -p .cache api:: diff --git a/README.md b/README.md index dda4c3fb967d7795e150df970f8c8a2070b58db2..98f4bd3383dd7c8f870f4b1ee858f0ad77b353cd 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ Install dependencies and prepare config file: make init.app ``` -This also creates a default configuration file at `config/engine.ini`. +This also creates a default configuration file at `config/engine.yaml`. For development install with: @@ -102,7 +102,7 @@ For development install with: make init.dev ``` -Note, if some configuration exists under `/etc/aura/engine.ini` the configuration by default is drawn from there. This overrides any configuration located in the local configuration file. +Note, if some configuration exists under `/etc/aura/engine.yaml` the configuration by default is drawn from there. This overrides any configuration located in the local configuration file. ### Initialize database @@ -116,13 +116,13 @@ This creates a database and tables with default password `1234`. ## Configuration -Edit the configuration file `config/engine.ini`. Verify or change at least these config options: +Edit the configuration file `config/engine.yaml`. Verify or change at least these config options: -```ini +```yaml # The password for the local caching database holding scheduling information -db_pass="1234" +db_pass: aura-engine-dbpass # The secret which is used to authenticate against Tank -api_tank_secret="aura-engine-secret" +api_tank_secret: aura-engine-secret ``` ## Running Engine diff --git a/config/sample.engine.docker.ini b/config/sample.engine.docker.ini deleted file mode 100644 index 44f0878330a1cfb35b839cb2782e886f117339b7..0000000000000000000000000000000000000000 --- a/config/sample.engine.docker.ini +++ /dev/null @@ -1,89 +0,0 @@ -############################################## -# Engine Configuration # -############################################## - -[general] -# Path to the engine-core socket directory relative to the engine project root -socket_dir="/srv/socket" -# Directory to store temporary data -cache_dir="/tmp" -# Directory where the log file resides -log_dir="logs" -# Possible values: debug, info, warning, error, critical -log_level="${AURA_ENGINE_LOG_LEVEL}" -# Details for the Station Fallback -fallback_show_name="${AURA_ENGINE_FALLBACK_SHOW_NAME}" -fallback_show_id="${AURA_ENGINE_FALLBACK_SHOW_ID}" - -[monitoring] -# Seconds how often the vitality of Engine Core should be checked (default=1) -heartbeat_frequency="${AURA_ENGINE_HEARTBEAT_FREQUENCY}" -# Host where heartbeat is sent to (disabled if empty string) -heartbeat_server="${AURA_ENGINE_HEARTBEAT_SERVER}" -# Some UDP port -heartbeat_port="${AURA_ENGINE_HEARTBEAT_SERVER_PORT}" - -[api] -## STEERING ## -# The URL to get the health status -api_steering_status="${AURA_STEERING_BASE_URL}api/v1/" -# The URL to get the Calendar via Steering -api_steering_calendar="${AURA_STEERING_BASE_URL}api/v1/playout" - -## TANK ## -# The session name which is used to authenticate against Tank -api_tank_session="${AURA_TANK_ENGINE_USER}" -# The secret which is used to authenticate against Tank -api_tank_secret="${AURA_TANK_ENGINE_PASSWORD}" -# The URL to get the health status -api_tank_status="${AURA_TANK_BASE_URL}healthz" -# The URL to get playlist details via Tank -api_tank_playlist="${AURA_TANK_BASE_URL}api/v1/playlists/${ID}" - -## ENGINE-API ## -# Engine ID (1 or 2) -api_engine_number=1 -# Engine API availability check -api_engine_status="${AURA_ENGINE_API_BASE_URL}api/v1/ui/" -# Engine API endpoint to store playlogs -api_engine_store_playlog="${AURA_ENGINE_API_BASE_URL}api/v1/playlog" -# Engine API endpoint to store clock information -api_engine_store_clock="${AURA_ENGINE_API_BASE_URL}api/v1/clock" -# Engine API endpoint to store health information -api_engine_store_health="${AURA_ENGINE_API_BASE_URL}api/v1/source/health/${ENGINE_NUMBER}" - -[scheduler] -# Database settings: Use 'postgresql' or 'mysql' -db_type="postgresql" -db_name="${AURA_ENGINE_DB_NAME}" -db_user="${AURA_ENGINE_DB_USER}" -db_pass="${AURA_ENGINE_DB_PASS}" -db_host="${AURA_ENGINE_DB_HOST}" -db_charset="utf8" -# Base path as seen by "engine-core", not accessed by "engine"; this is required to construct the absolute audio file path (check "Audio Store" in the docs) -# Either provide an absolute base path or a relative one starting in the `engine` directory. In case of `engine-core` running in docker use `/var/audio/source` -audio_source_folder="/var/audio/source" -audio_source_extension=".flac" -# Folder holding M3U Playlists to be scheduled in form of Engine Playlists (similar as audio source folder above) -audio_playlist_folder="/var/audio/playlist" -# Offset in seconds how long it takes for Liquidsoap to actually execute a scheduler command; Crucial to keep things in sync -engine_latency_offset="${AURA_ENGINE_LATENCY_OFFSET}" -# How often should the calendar be fetched in seconds. This determines the time of the last changes applied, before a specific show is aired -fetching_frequency=30 -# The scheduling window defines when the entries of each timeslot are queued for play-out. The windows start at (timeslot.start - window_start) seconds -# and ends at (timeslot.end - window.end) seconds. Its also worth noting, that timeslots can only be deleted before the start of the window. -scheduling_window_start=60 -scheduling_window_end=60 -# How many seconds before the actual schedule time the entry should be pre-loaded. Note to provide enough timeout for -# contents which take longer to load (big files, bad connectivity to streams etc.). If the planned start time is in -# the past the offset is ignored and the entry is played as soon as possible -preload_offset=15 -# Sometimes it might take longer to get a stream connected. Here you can define a viable length. -# But note, that this may affect the preloading time (see `preload_offset`), hence affecting the -# overall playout, its delays and possible fallbacks -input_stream_retry_delay=1 -input_stream_max_retries=10 -input_stream_buffer=3.0 -# Fade duration when selecting another mixer input (seconds) -fade_in_time="${AURA_ENGINE_FADE_IN_TIME}" -fade_out_time="${AURA_ENGINE_FADE_OUT_TIME}" diff --git a/config/sample.engine.docker.yaml b/config/sample.engine.docker.yaml new file mode 100644 index 0000000000000000000000000000000000000000..bf5fd3fc30b4167b961f676d860ee61bbc5aa5eb --- /dev/null +++ b/config/sample.engine.docker.yaml @@ -0,0 +1,128 @@ +############################################## +# Engine Configuration # +############################################## + +general: + log: + # Directory where the log file resides + directory: logs + # Possible values: debug, info, warning, error, critical + level: ${AURA_ENGINE_LOG_LEVEL} + + # Path to the engine-core socket directory relative to the engine project root + socket_dir: /srv/socket + # Directory to store temporary data + cache_dir: /tmp + + # Details for the Station Fallback + fallback: + show_name: ${AURA_ENGINE_FALLBACK_SHOW_NAME} + show_id: ${AURA_ENGINE_FALLBACK_SHOW_ID} + +monitoring: + mail: + # Mail server credentials for sending email notifications (Admin and Programme Coordination) + host: mail.your-radio.org + port: 587 + user: aura@subsquare.at + pwd: ---SECRET--PASSWORD--- + + coordinator: + # Set to "true" if you want to notify programme-coordinators about about fallback situations, otherwise "false" + enabled: false + # If you want to address multiple programme-coordinators separate their emails by space + mail: programme-coordinator@your-radio.org + + admin: + # Set to "true" if you want to notify admins about incidents, otherwise "false" + enabled: false + # If you want to address multiple administrators separate their emails by space + mail: david@subsquare.at + + # The FROM email address used when sending + from: monitoring@aura.engine + # A subject prefix allows applying filter rules in your mail client + subject_prefix: "[AURA Engine]" # default: [AURA Engine] + + heartbeat: + # Seconds how often the vitality of Engine Core should be checked (default: 1) + frequency: ${AURA_ENGINE_HEARTBEAT_FREQUENCY} + # Host where heartbeat is sent to (disabled if empty string) + host: ${AURA_ENGINE_HEARTBEAT_SERVER} + # Some UDP port + port: ${AURA_ENGINE_HEARTBEAT_SERVER_PORT} + +api: + ## STEERING ## + steering: + # The URL to get the health status + status: ${AURA_STEERING_BASE_URL}api/v1/ + # The URL to get the Calendar via Steering + calendar: ${AURA_STEERING_BASE_URL}api/v1/playout + + ## TANK ## + tank: + # The session name which is used to authenticate against Tank + session: ${AURA_TANK_ENGINE_USER} + # The secret which is used to authenticate against Tank + secret: ${AURA_TANK_ENGINE_PASSWORD} + # The URL to get the health status + status: ${AURA_TANK_BASE_URL}healthz + # The URL to get playlist details via Tank + playlist: ${AURA_TANK_BASE_URL}api/v1/playlists/${ID} + + ## ENGINE-API ## + engine: + # Engine ID (1 or 2) + number: 1 + # Engine API availability check + status: ${AURA_ENGINE_API_BASE_URL}api/v1/ui/ + # Engine API endpoint to store playlogs + store_playlog: ${AURA_ENGINE_API_BASE_URL}api/v1/playlog + # Engine API endpoint to store clock information + store_clock: ${AURA_ENGINE_API_BASE_URL}api/v1/clock + # Engine API endpoint to store health information + store_health: ${AURA_ENGINE_API_BASE_URL}api/v1/source/health/${ENGINE_NUMBER} +scheduler: + # Database settings: Use 'postgresql', 'sqlite' or 'mysql'. In case of SQLite the "db_name" is the name of the file. + db: + type: postgresql + name: ${AURA_ENGINE_DB_NAME} + user: ${AURA_ENGINE_DB_USER} + pwd: ${AURA_ENGINE_DB_PASS} + host: ${AURA_ENGINE_DB_HOST} + charset: utf8 + + # Base path as seen by "engine-core", not accessed by "engine"; this is required to construct the absolute audio file path (check "Audio Store" in the docs) + # Either provide an absolute base path or a relative one starting in the `engine` directory. In case of `engine-core` running in docker use `/var/audio/source` + audio: + source_folder: /var/audio/source + source_extension: .flac + # Folder holding M3U Playlists to be scheduled in form of Engine Playlists (similar as audio source folder above) + playlist_folder: /var/audio/playlist + # Offset in seconds how long it takes for Liquidsoap to actually execute a scheduler command; Crucial to keep things in sync + engine_latency_offset: ${AURA_ENGINE_LATENCY_OFFSET} + + # How often should the calendar be fetched in seconds. This determines the time of the last changes applied, before a specific show is aired + fetching_frequency: 30 + # The scheduling window defines when the entries of each timeslot are queued for play-out. The windows start at (timeslot.start - window_start) seconds + # and ends at (timeslot.end - window.end) seconds. Its also worth noting, that timeslots can only be deleted before the start of the window. + scheduling_window_start: 60 + scheduling_window_end: 60 + # How many seconds before the actual schedule time the entry should be pre-loaded. Note to provide enough timeout for + # contents which take longer to load (big files, bad connectivity to streams etc.). If the planned start time is in + # the past the offset is ignored and the entry is played as soon as possible + preload_offset: 15 + + # Sometimes it might take longer to get a stream connected. Here you can define a viable length. + # But note, that this may affect the preloading time (see `preload_offset`), hence affecting the + # overall playout, its delays and possible fallbacks + input_stream: + retry_delay: 1 + max_retries: 10 + buffer: 3.0 + + # Fade duration when selecting another mixer input (seconds) + fade: + in_time: ${AURA_ENGINE_FADE_IN_TIME} + out_time: ${AURA_ENGINE_FADE_OUT_TIME} diff --git a/config/sample.engine.ini b/config/sample.engine.ini deleted file mode 100644 index 875955bf567341bd1dca8459077b5ccc1a3efab0..0000000000000000000000000000000000000000 --- a/config/sample.engine.ini +++ /dev/null @@ -1,89 +0,0 @@ -############################################## -# Engine Configuration # -############################################## - -[general] -# Path to the engine-core socket directory relative to the engine project root -socket_dir="../engine-core/socket" -# Directory to store temporary data -cache_dir="./.cache" -# Directory where the log file resides -log_dir="logs" -# Possible values: debug, info, warning, error, critical -log_level="info" -# Details for the Station Fallback -fallback_show_name="Random Music" -fallback_show_id="-1" - -[monitoring] -# Seconds how often the vitality of Engine Core should be checked (default=1) -heartbeat_frequency=1 -# Host where heartbeat is sent to (disabled if empty string) -heartbeat_server="" -# Some UDP port -heartbeat_port=43334 - -[api] -## STEERING ## -# The URL to get the health status -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" - -## TANK ## -# The session name which is used to authenticate against Tank -api_tank_session="engine" -# The secret which is used to authenticate against Tank -api_tank_secret="rather-secret" -# The URL to get the health status -api_tank_status="http://localhost:8040/healthz" -# The URL to get playlist details via Tank -api_tank_playlist="http://localhost:8040/api/v1/playlists/${ID}" - -## ENGINE-API ## -# Engine ID (1 or 2) -api_engine_number=1 -# Engine API availability check -api_engine_status="http://localhost:8008/api/v1/ui/" -# Engine API endpoint to store playlogs -api_engine_store_playlog="http://localhost:8008/api/v1/playlog" -# Engine API endpoint to store clock information -api_engine_store_clock="http://localhost:8008/api/v1/clock" -# Engine API endpoint to store health information -api_engine_store_health="http://localhost:8008/api/v1/source/health/${ENGINE_NUMBER}" - -[scheduler] -# Database settings: Use 'postgresql', 'sqlite' or 'mysql'. In case of SQLite the "db_name" is the name of the file. -db_type="postgresql" -db_name="aura_engine" -db_user="aura_engine" -db_pass="---SECRET--PASSWORD---" -db_host="localhost" -db_charset="utf8" -# Base path as seen by "engine-core", not accessed by "engine"; this is required to construct the absolute audio file path (check "Audio Store" in the docs) -# Either provide an absolute base path or a relative one starting in the `engine` directory. In case of `engine-core` running in docker use `/var/audio/source` -audio_source_folder="../engine-core/audio/source" -audio_source_extension=".flac" -# Folder holding M3U Playlists to be scheduled in form of Engine Playlists (similar as audio source folder above) -audio_playlist_folder="../engine-core/audio/playlist" -# Offset in seconds how long it takes for Liquidsoap to actually execute a scheduler command; Crucial to keep things in sync -engine_latency_offset=0.5 -# How often should the calendar be fetched in seconds. This determines the time of the last changes applied, before a specific show is aired -fetching_frequency=30 -# The scheduling window defines when the entries of each timeslot are queued for play-out. The windows start at (timeslot.start - window_start) seconds -# and ends at (timeslot.end - window.end) seconds. Its also worth noting, that timeslots can only be deleted before the start of the window. -scheduling_window_start=60 -scheduling_window_end=60 -# How many seconds before the actual schedule time the entry should be pre-loaded. Note to provide enough timeout for -# contents which take longer to load (big files, bad connectivity to streams etc.). If the planned start time is in -# the past the offset is ignored and the entry is played as soon as possible -preload_offset=15 -# Sometimes it might take longer to get a stream connected. Here you can define a viable length. -# But note, that this may affect the preloading time (see `preload_offset`), hence affecting the -# overall playout, its delays and possible fallbacks -input_stream_retry_delay=1 -input_stream_max_retries=10 -input_stream_buffer=3.0 -# Fade duration when selecting another mixer input (seconds) -fade_in_time="1.5" -fade_out_time="1.5" diff --git a/config/engine.yaml b/config/sample.engine.yaml similarity index 100% rename from config/engine.yaml rename to config/sample.engine.yaml diff --git a/docs/developer-guide.md b/docs/developer-guide.md index 925900624b3c17f658e369b0eed60bd55f594fe1..0dbcc84321eaf04dc176099c4632c168a9f4ce49 100644 --- a/docs/developer-guide.md +++ b/docs/developer-guide.md @@ -118,12 +118,12 @@ point in time and the involved phase before: The start and the end of the window is defined by the start of the timeslot minus a configured amount of seconds (see `scheduling_window_start` and `scheduling_window_end` - in `engine.ini`). The actual start of the window is calculated by (timeslot start - window start) + in `engine.yaml`). The actual start of the window is calculated by (timeslot start - window start) and the end by (timeslot end - window end) During the scheduling window, the external API Endpoints are pulled continuously, to check for updated timeslots and related playlists. Also, any changes to playlists and - its entries are respected within that window (see `fetching_frequency` in `engine.ini`). + its entries are respected within that window (see `fetching_frequency` in `engine.yaml`). > Important: It is vital that the the scheduling window is wider than the fetching frequency. > Otherwise one fetch might never hit a scheduling window, hence not being able to schedule stuff. @@ -136,7 +136,7 @@ point in time and the involved phase before: - **Queuing and Pre-Loading**: Before any playlist entries of the timeslot can be turned into sound, they need to be queued and pre-loaded. Ideally the pre-loading happens somewhat before the scheduled play-out time to avoid any delays in timing. Set the maximum time reserved for - pre-loading in your configuration (compare `preload_offset`in `engine.ini`). + pre-loading in your configuration (compare `preload_offset`in `engine.yaml`). If there is not enough time to reserve the given amount of time for preloading (i.e. some entry should have started in the past already) the offset is ignored and the entry is played as soon as possible. diff --git a/scripts/initialize-systemd.sh b/scripts/initialize-systemd.sh index 7fce56f158c1a0f4dce10b6500a1914a816a7e0c..3a41a810eabcacb5b2f3cf9d4afb92769a1f3ad5 100755 --- a/scripts/initialize-systemd.sh +++ b/scripts/initialize-systemd.sh @@ -6,7 +6,7 @@ # You'll need sudo/root privileges. # -echo "Set Ownership of '/opt/aura/engine', '/var/log/aura/' and '/etc/aura/engine.ini' to Engine User" +echo "Set Ownership of '/opt/aura/engine', '/var/log/aura/' and '/etc/aura/engine.yaml' to Engine User" chown -R engineuser:engineuser /opt/aura chown -R engineuser:engineuser /etc/aura chown -R engineuser:engineuser /var/log/aura diff --git a/src/aura_engine/base/config.py b/src/aura_engine/base/config.py index a5bfaebfb87c95ffe4a0121fc74c34a8bf453e9b..8151bd1602f0a16a46ac67a061b622804d6331e4 100644 --- a/src/aura_engine/base/config.py +++ b/src/aura_engine/base/config.py @@ -90,7 +90,7 @@ template = { class AuraConfig: """ - Holds the Engine Configuration as in the file `engine.ini`. + Creates config by reading yaml file according to template above. """ _instance = None