Skip to content
Snippets Groups Projects
Commit 915aa8b7 authored by Auke Klazema's avatar Auke Klazema
Browse files

Merge branch 'master' into L2SS-704

parents 153c32fb 2a3ef002
No related branches found
No related tags found
1 merge request!302L2SS-704: Implement AntennaField device with tests
Showing
with 312 additions and 5 deletions
...@@ -27,3 +27,4 @@ tangostationcontrol/docs/build ...@@ -27,3 +27,4 @@ tangostationcontrol/docs/build
**/pending_log_messages.db **/pending_log_messages.db
**/.eggs **/.eggs
docker-compose/alerta-web/alerta-secrets.json
...@@ -104,6 +104,7 @@ docker_build_image_all: ...@@ -104,6 +104,7 @@ docker_build_image_all:
- bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-boot latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-boot latest
- bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-docker latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-docker latest
- bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-observation_control latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-observation_control latest
- bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-pdu latest
- bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-recv latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-recv latest
- bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-sdp latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-sdp latest
- bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-sst latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-sst latest
...@@ -254,6 +255,17 @@ docker_build_image_device_apspu: ...@@ -254,6 +255,17 @@ docker_build_image_device_apspu:
script: script:
# Do not remove 'bash' or statement will be ignored by primitive docker shell # Do not remove 'bash' or statement will be ignored by primitive docker shell
- bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-apspu $tag - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-apspu $tag
docker_build_image_device_pdu:
extends: .base_docker_images_except
only:
refs:
- merge_requests
changes:
- docker-compose/device-pdu.yml
- docker-compose/lofar-device-base/*
script:
# Do not remove 'bash' or statement will be ignored by primitive docker shell
- bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-pdu $tag
docker_build_image_device_tilebeam: docker_build_image_device_tilebeam:
extends: .base_docker_images_except extends: .base_docker_images_except
only: only:
...@@ -474,6 +486,7 @@ integration_test_docker: ...@@ -474,6 +486,7 @@ integration_test_docker:
fi fi
- apk add --update make bash docker-compose - apk add --update make bash docker-compose
- apk add --update bind-tools - apk add --update bind-tools
- apk add --update postgresql14-client gzip
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script: script:
- touch /root/.Xauthority - touch /root/.Xauthority
...@@ -498,6 +511,7 @@ integration_test_docker: ...@@ -498,6 +511,7 @@ integration_test_docker:
echo "Saving log for container $container" echo "Saving log for container $container"
docker logs "${container}" >& "log/${container}.log" docker logs "${container}" >& "log/${container}.log"
done done
PGPASSWORD=password pg_dump --host=docker --username=postgres hdb 2>log/archiver-timescale-dump.log | gzip > log/archiver-timescale-dump.txt.gz
wheel_packaging: wheel_packaging:
stage: packaging stage: packaging
artifacts: artifacts:
......
...@@ -21,6 +21,13 @@ ...@@ -21,6 +21,13 @@
} }
} }
}, },
"PDU": {
"STAT": {
"PDU": {
"STAT/PDU/1": {}
}
}
},
"TileBeam": { "TileBeam": {
"STAT": { "STAT": {
"TileBeam": { "TileBeam": {
......
...@@ -357,6 +357,24 @@ ...@@ -357,6 +357,24 @@
"902", "902",
"902", "902",
"902" "902"
],
"TR_fpga_mask_RW_default": [
"True",
"True",
"True",
"True",
"False",
"False",
"False",
"False",
"False",
"False",
"False",
"False",
"False",
"False",
"False",
"False"
] ]
} }
} }
......
...@@ -35,7 +35,7 @@ else ...@@ -35,7 +35,7 @@ else
mkdir -p /tmp/tangostationcontrol mkdir -p /tmp/tangostationcontrol
python3 setup.py build --build-base /tmp/tangostationcontrol egg_info --egg-base /tmp/tangostationcontrol bdist_wheel --dist-dir /tmp/tangostationcontrol || exit 1 python3 setup.py build --build-base /tmp/tangostationcontrol egg_info --egg-base /tmp/tangostationcontrol bdist_wheel --dist-dir /tmp/tangostationcontrol || exit 1
# shellcheck disable=SC2012 # shellcheck disable=SC2012
sudo pip install "$(ls -Art /tmp/tangostationcontrol/*.whl | tail -n 1)" pip install "$(ls -Art /tmp/tangostationcontrol/*.whl | tail -n 1)"
fi fi
# Return to the stored the directory, this preserves the working_dir argument in # Return to the stored the directory, this preserves the working_dir argument in
......
FROM alerta/alerta-web FROM alerta/alerta-web
RUN pip install git+https://github.com/alerta/alerta-contrib.git#subdirectory=plugins/slack RUN bash -c 'source /venv/bin/activate; pip install git+https://github.com/alerta/alerta-contrib.git#subdirectory=plugins/slack'
RUN bash -c 'source /venv/bin/activate; pip install git+https://github.com/alerta/alerta-contrib.git#subdirectory=plugins/jira'
COPY grafana-plugin /tmp/grafana-plugin
RUN bash -c 'source /venv/bin/activate; pip install /tmp/grafana-plugin'
COPY lofar-plugin /tmp/lofar-plugin
RUN bash -c 'source /venv/bin/activate; pip install /tmp/lofar-plugin'
COPY alertad.conf /app/alertad.conf
COPY alerta.conf /app/alerta.conf
COPY config.json /web/config.json
You need:
* Your own Slack App:
* Give it channel write rights
* Get the OAuth token
* Install it in your slack
* Invite the app into your channel
* Feed the OAuth token to the config
* Add it to alerta-secrets.json
* Grafana:
* By default, grafana resends alarms every 4h, configure this in the notification settings to faster resend deleted alarms for testing
* Add alerts by hand
* add "Summary" as alert text
* add label "severity": "major"/"minor"/etc (see https://docs.alerta.io/webui/configuration.html#severity-colors)
* Create alerta-secrets.json in this directory:
Example alerta-secrets.json:
{
"SLACK_TOKEN": "xoxb-...",
"SLACK_CHANNEL": "#lofar20-alerta"
}
{
"SLACK_TOKEN": "xoxb-get-this-from-your-slack-app",
"SLACK_CHANNEL": "#your-channel"
}
[DEFAULT]
sslverify = no
output = presto
endpoint = http://localhost:8080/api
timezone = Europe/London
key = NpzX0z_fX8TVKZtXpzop-pi2MhaGnLawKVqbJBoA
debug = yes
DEBUG = True
SECRET = "T=&7xvF2S&x7w_JAcq$h1x5ocfA)8H2i"
# Allow non-admin views
CUSTOMER_VIEWS = True
# Never timeout alerts
ALERT_TIMEOUT = 0
# Auto unack after a day
ACK_TIMEOUT = 24 * 3600
# Auto unshelve after 2 hours
SHELVE_TIMEOUT = 2 * 3600
# Use custom date formats
DATE_FORMAT_MEDIUM_DATE = "dd DD/MM HH:mm"
DATE_FORMAT_LONG_DATE = "yyyy-MM-DD HH:mm:ss.sss"
# Default overview settings
COLUMNS = ['severity', 'status', 'createTime', 'lastReceiveTime', 'resource', 'grafanaDashboardHtml', 'grafanaPanelHtml', 'event', 'text']
DEFAULT_FILTER = {'status': ['open']}
SORT_LIST_BY = "createTime"
AUTO_REFRESH_INTERVAL = 5000 # ms
# ------------------------------------
# Plugin configuration
# ------------------------------------
PLUGINS = ['reject', 'blackout', 'acked_by', 'enhance', 'grafana', 'lofar', 'slack']
# Slack plugin settings, see https://github.com/alerta/alerta-contrib/tree/master/plugins/slack
import os, json
with open("/run/secrets/alerta-secrets") as secrets_file:
secrets = json.load(secrets_file)
SLACK_WEBHOOK_URL = 'https://slack.com/api/chat.postMessage'
SLACK_TOKEN = secrets["SLACK_TOKEN"]
SLACK_CHANNEL = secrets["SLACK_CHANNEL"]
SLACK_ATTACHMENTS = True
BASE_URL = os.environ.get("BASE_URL", "")
# for the Slack message configuration syntax, see https://api.slack.com/methods/chat.postMessage
# and https://app.slack.com/block-kit-builder
SLACK_PAYLOAD = {
"channel": "{{ channel }}",
"emoji": ":fire:",
"text": "*{{ alert.severity|capitalize }}* :: *{{ alert.resource }}* :: _{{ alert.event }}_\n\n```{{ alert.text }}```",
"attachments": [{
"color": "{{ color }}",
"fields": [
{"title": "Device", "value": "{{ alert.attributes.lofarDevice }}", "short": True },
{"title": "Attribute", "value": "{{ alert.attributes.lofarAttribute }}", "short": True },
{"title": "Resource", "value": "{{ alert.resource }}", "short": True },
{"title": "Status", "value": "{{ status|capitalize }}", "short": True },
{"title": "Dashboards", "value": "<{{ config.BASE_URL }}/#/alert/{{ alert.id }}|Alerta>\nGrafana <{{ alert.attributes.grafanaDashboardUrl }}|Dashboard> <{{ alert.attributes.grafanaPanelUrl }}|Panel>", "short": True },
{"title": "Configure", "value": "Grafana <{{ alert.attributes.grafanaAlertUrl }}|View> <{{ alert.attributes.grafanaSilenceUrl }}|Silence>", "short": True },
],
}]
}
{"endpoint": "/api"}
import os
import json
import logging
from alerta.plugins import PluginBase
LOG = logging.getLogger()
class EnhanceGrafana(PluginBase):
"""
Plugin for parsing alerts coming from Grafana
"""
def pre_receive(self, alert, **kwargs):
# Parse Grafana-specific fields
alert.attributes['grafanaStatus'] = alert.raw_data.get('status', '')
def htmlify(link: str, desc: str) -> str:
return f'<a href="{link}" target="_blank">{desc}</a>';
# User-specified "Panel ID" annotation
panelURL = alert.raw_data.get('panelURL', '')
if panelURL:
alert.attributes['grafanaPanelUrl'] = panelURL
alert.attributes['grafanaPanelHtml'] = htmlify(panelURL, "Grafana Panel")
# User-specified "Dashboard UID" annotation
dashboardURL = alert.raw_data.get('dashboardURL', '')
if dashboardURL:
alert.attributes['grafanaDashboardUrl'] = dashboardURL
alert.attributes['grafanaDashboardHtml'] = htmlify(dashboardURL, "Grafana Dashboard")
alertURL = alert.raw_data.get('generatorURL', '')
if alertURL:
# expose alert view URL, as user may not have edit rights
# Convert from
# http://host:3000/alerting/kujybCynk/edit
# to
# http://host:3000/alerting/grafana/kujybCynk/view
alertURL = alertURL.replace("/alerting/", "/alerting/grafana/").replace("/edit", "/view")
alert.attributes['grafanaAlertUrl'] = alertURL
alert.attributes['grafanaAlertHtml'] = htmlify(alertURL, "Grafana Alert")
silenceURL = alert.raw_data.get('silenceURL', '')
if silenceURL:
alert.attributes['grafanaSilenceUrl'] = silenceURL
alert.attributes['grafanaSilenceHtml'] = htmlify(silenceURL, "Grafana Silence Alert")
return alert
def post_receive(self, alert, **kwargs):
return
def status_change(self, alert, status, text, **kwargs):
return
def take_action(self, alert, action, text, **kwargs):
raise NotImplementedError
from setuptools import setup, find_packages
version = '1.0.0'
setup(
name="alerta-grafana",
version=version,
description='Alerta plugin for enhancing Grafana alerts',
url='https://git.astron.nl/lofar2.0/tango',
license='Apache License 2.0',
author='Jan David Mol',
author_email='mol@astron.nl',
packages=find_packages(),
py_modules=['alerta_grafana'],
include_package_data=True,
zip_safe=True,
entry_points={
'alerta.plugins': [
'grafana = alerta_grafana:EnhanceGrafana'
]
},
python_requires='>=3.5'
)
import os
import json
import logging
from alerta.plugins import PluginBase
LOG = logging.getLogger()
class EnhanceLOFAR(PluginBase):
"""
Plugin for enhancing alerts with LOFAR-specific information
"""
def pre_receive(self, alert, **kwargs):
# Parse LOFAR-specific fields
for tag in alert.tags:
try:
key, value = tag.split("=", 1)
except ValueError:
continue
if key == "device":
alert.attributes['lofarDevice'] = value
if key == "name":
alert.attributes['lofarAttribute'] = value
if key == "station":
alert.resource = value
return alert
def post_receive(self, alert, **kwargs):
return
def status_change(self, alert, status, text, **kwargs):
return
def take_action(self, alert, action, text, **kwargs):
raise NotImplementedError
from setuptools import setup, find_packages
version = '1.0.0'
setup(
name="alerta-lofar",
version=version,
description='Alerta plugin for enhancing LOFAR alerts',
url='https://git.astron.nl/lofar2.0/tango',
license='Apache License 2.0',
author='Jan David Mol',
author_email='mol@astron.nl',
packages=find_packages(),
py_modules=['alerta_lofar'],
include_package_data=True,
zip_safe=True,
entry_points={
'alerta.plugins': [
'lofar = alerta_lofar:EnhanceLOFAR'
]
},
python_requires='>=3.5'
)
{"test":[{"name":"test2","interval":"10s","rules":[{"expr":"","for":"20s","labels":{"severity":"major"},"annotations":{"__dashboardUid__":"nC8N_kO7k","__panelId__":"9","summary":"My test alert"},"grafana_alert":{"id":3,"orgId":1,"title":"FPGA processing error 2","condition":"B","data":[{"refId":"A","queryType":"","relativeTimeRange":{"from":600,"to":0},"datasourceUid":"ZqArtG97z","model":{"exemplar":false,"expr":"device_attribute{device=\"stat/sdp/1\",name=\"FPGA_error_R\"}","format":"time_series","group":[],"hide":false,"interval":"","intervalMs":1000,"legendFormat":"","maxDataPoints":43200,"metricColumn":"name","rawQuery":true,"rawSql":"SELECT\n data_time AS \"time\",\n x::text,\n device,\n name,\n case when value then 1 else 0 end AS value\nFROM lofar_array_boolean\nWHERE\n $__timeFilter(data_time) AND\n name = 'fpga_error_r'\nORDER BY 1,2","refId":"A","select":[[{"params":["x"],"type":"column"}],[{"params":["value"],"type":"column"}]],"table":"lofar_array_boolean","timeColumn":"data_time","timeColumnType":"timestamptz","where":[{"name":"$__timeFilter","params":[],"type":"macro"},{"datatype":"text","name":"","params":["name","=","'fpga_error_r'"],"type":"expression"}]}},{"refId":"B","queryType":"","relativeTimeRange":{"from":0,"to":0},"datasourceUid":"-100","model":{"conditions":[{"evaluator":{"params":[0,0],"type":"gt"},"operator":{"type":"and"},"query":{"params":[]},"reducer":{"params":[],"type":"avg"},"type":"query"}],"datasource":{"type":"__expr__","uid":"__expr__"},"expression":"A","hide":false,"intervalMs":1000,"maxDataPoints":43200,"reducer":"last","refId":"B","settings":{"mode":"dropNN"},"type":"reduce"}}],"updated":"2022-04-04T14:18:48Z","intervalSeconds":10,"version":1,"uid":"waXdSCynk","namespace_uid":"9DkbdYy7z","namespace_id":6,"rule_group":"test2","no_data_state":"OK","exec_err_state":"Error"}}]},{"name":"test","interval":"10s","rules":[{"expr":"","for":"20s","labels":{"severity":"major"},"annotations":{"__dashboardUid__":"nC8N_kO7k","__panelId__":"9","summary":"My test alert"},"grafana_alert":{"id":2,"orgId":1,"title":"FPGA processing error","condition":"B","data":[{"refId":"A","queryType":"","relativeTimeRange":{"from":600,"to":0},"datasourceUid":"ZqArtG97z","model":{"exemplar":false,"expr":"device_attribute{device=\"stat/sdp/1\",name=\"FPGA_error_R\"}","format":"time_series","group":[],"hide":false,"interval":"","intervalMs":1000,"legendFormat":"","maxDataPoints":43200,"metricColumn":"name","rawQuery":true,"rawSql":"SELECT\n data_time AS \"time\",\n x::text,\n device,\n name,\n case when value then 1 else 0 end AS value\nFROM lofar_array_boolean\nWHERE\n $__timeFilter(data_time) AND\n name = 'fpga_error_r'\nORDER BY 1,2","refId":"A","select":[[{"params":["x"],"type":"column"}],[{"params":["value"],"type":"column"}]],"table":"lofar_array_boolean","timeColumn":"data_time","timeColumnType":"timestamptz","where":[{"name":"$__timeFilter","params":[],"type":"macro"},{"datatype":"text","name":"","params":["name","=","'fpga_error_r'"],"type":"expression"}]}},{"refId":"B","queryType":"","relativeTimeRange":{"from":0,"to":0},"datasourceUid":"-100","model":{"conditions":[{"evaluator":{"params":[0,0],"type":"gt"},"operator":{"type":"and"},"query":{"params":[]},"reducer":{"params":[],"type":"avg"},"type":"query"}],"datasource":{"type":"__expr__","uid":"__expr__"},"expression":"A","hide":false,"intervalMs":1000,"maxDataPoints":43200,"reducer":"last","refId":"B","settings":{"mode":"dropNN"},"type":"reduce"}}],"updated":"2022-04-04T14:16:22Z","intervalSeconds":10,"version":1,"uid":"MIt4Ijs7k","namespace_uid":"9DkbdYy7z","namespace_id":6,"rule_group":"test","no_data_state":"OK","exec_err_state":"Error"}}]}]}
\ No newline at end of file
...@@ -3,6 +3,10 @@ version: '2.1' ...@@ -3,6 +3,10 @@ version: '2.1'
volumes: volumes:
alerta-postgres-data: {} alerta-postgres-data: {}
secrets:
alerta-secrets:
file: alerta-web/alerta-secrets.json
services: services:
alerta-web: alerta-web:
build: alerta-web build: alerta-web
...@@ -13,13 +17,16 @@ services: ...@@ -13,13 +17,16 @@ services:
- "8081:8080" - "8081:8080"
depends_on: depends_on:
- alerta-db - alerta-db
secrets:
- alerta-secrets
environment: environment:
- DEBUG=1 # remove this line to turn DEBUG off - DEBUG=1 # remove this line to turn DEBUG off
- DATABASE_URL=postgres://postgres:postgres@alerta-db:5432/monitoring - DATABASE_URL=postgres://postgres:postgres@alerta-db:5432/monitoring
- BASE_URL=http://${HOSTNAME}:8081
- DASHBOARD_URL=http://${HOSTNAME}:8081
- AUTH_REQUIRED=True - AUTH_REQUIRED=True
- ADMIN_USERS=admin #default password: alerta - ADMIN_USERS=admin #default password: alerta
- ADMIN_KEY=demo-key - ADMIN_KEY=demo-key
- PLUGINS=reject,blackout,normalise,enhance
restart: always restart: always
alerta-db: alerta-db:
......
...@@ -21,5 +21,5 @@ services: ...@@ -21,5 +21,5 @@ services:
max-file: "10" max-file: "10"
networks: networks:
- control - control
entrypoint: python3 pypcc2.py --simulator --port 4843 --config APSCTTR entrypoint: hwtr --simulator --port 4843 --config APSCTTR
restart: on-failure restart: on-failure
...@@ -21,5 +21,5 @@ services: ...@@ -21,5 +21,5 @@ services:
max-file: "10" max-file: "10"
networks: networks:
- control - control
entrypoint: python3 pypcc2.py --simulator --port 4842 --config APSPUTR entrypoint: hwtr --simulator --port 4842 --config APSPUTR
restart: on-failure restart: on-failure
version: '2' version: '2'
volumes:
archiver-timescale-data: {}
services: services:
archiver-timescale: archiver-timescale:
image: timescaledb image: timescaledb
...@@ -12,6 +15,8 @@ services: ...@@ -12,6 +15,8 @@ services:
- "5432:5432/tcp" - "5432:5432/tcp"
extra_hosts: extra_hosts:
- "host.docker.internal:host-gateway" - "host.docker.internal:host-gateway"
volumes:
- archiver-timescale-data:/var/lib/postgresql/data
depends_on: depends_on:
- databaseds - databaseds
environment: environment:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment