Notification Drone avec Gotify

Gotify est un serveur de notification en Go. Il permet de lui envoyer via une API du json avec une simple requête curl ou depuis du code.
Il propose une interface web pour créer des applications qui génère une token nécessaire à l’envoi des messages mais surtout une application android. Ainsi on pourra recevoir sur son téléphone des alertes et notifications envoyées par ses scripts et programmes.

Drone

L’idée est ici de l’utiliser pour l’ajouter dans un pipeline Drone afin d’être notifié du statut d’un déploiement. Jusqu’à présent j’utilisais Telegram (voir l’article un plugin drone pour telegram) cependant imposer une messagerie n’est pas forcément l’idéal dans tous les cas. De plus l’interface web de Gotify peut être utilisée comme moniteur des déploiements.

Gotify serveur

La première étape est de créer une image Docker car il n’y en a pas pour ARM64. Le développeur propose un binaire ARM64 ce qui simplifie le Dockerfile

cat Dockerfile.arm64v8 

FROM arm64v8/debian:stable-slim
ADD https://github.com/gotify/server/releases/download/v2.0.5/gotify-linux-arm64.zip /
RUN apt-get update &&\
    apt-get install -y unzip &&\
    unzip /gotify-linux-arm64.zip -d /
EXPOSE 80
ENTRYPOINT ["/gotify-linux-arm64"]

Le docker compose

cat gotify-arm64v8.yml 

version: "3"
services:
  gotify:
    image: fredix/arm64v8-gotify:2.0.5
    env_file: .env.production-server
    networks:
      - traefik-net
    ports:
      - 80
    volumes:
      - /swarm/volumes/gotify:/app/data
    deploy:
      placement:
        constraints:
          - node.labels.location == cloud-arm64
      labels:
        - "traefik.port=80"
        - "traefik.docker.network=traefik-net"
        - "traefik.frontend.rule=Host:gotify.fredix.xyz"


networks:
  traefik-net:
    external: true

le fichier .env.production-server contient les variables d’environnement qui servent à configurer le serveur. J’ai choisi sqlite mais si de nombreuses notifications sont prévues il vaut sans doute mieux utiliser un SGBD.

cat .env.production-server 

GOTIFY_DATABASE_DIALECT=sqlite3
GOTIFY_DATABASE_CONNECTION=gotify.db
GOTIFY_DEFAULTUSER_NAME=fredix
GOTIFY_DEFAULTUSER_PASS=PASS
GOTIFY_PASSSTRENGTH=10
GOTIFY_UPLOADEDIMAGESDIR=images
GOTIFY_PLUGINSDIR=plugins

on lance la stack

docker stack deploy --compose-file=gotify-arm64v8.yml gotify-arm64

IHM

l’interface permet de créer des utilisateurs et des applications.

gotify_1.png

gotify_2.png

On test que tout fonctionne avec un curl

curl -X POST "https://gotify.fredix.xyz/message?token=TOKEN" -F "title=test" 
-F "message=hello world" -F "priority=5"      

{"id":21,"appid":1,"message":"hello world","title":"test","priority":5,"date":"2019-06-09T19:02:03.800809406Z"}%                                               

gotify_4.png

Et sur android

gotify_5.png

Drone plugin

Le marketplace de Drone ne proposant pas de plugin Gotify j’en ai développé un rapidement en Go : drone-gotify, l’image ARM64v8 est sur le hub docker : fredix/arm64v8-alpine-drone-gotify. L’exemple de code Go fait 2 lignes : https://gotify.net/docs/more-pushmsg#golang, celui pour Drone fait à peine plus : https://docs.drone.io/plugins/examples/golang/. Le code suivant fait donc le boulot

package main

import (
	"net/http"
	"net/url"
	"os"
	"log"
)

func main() {
	token := os.Getenv("PLUGIN_GOTIFYTOKEN")
	endpoint := os.Getenv("PLUGIN_GOTIFYENDPOINT")
	title := os.Getenv("PLUGIN_GOTIFYTITLE")
	message := os.Getenv("PLUGIN_MESSAGE")
	priority := os.Getenv("PLUGIN_GOTIFYPRIORITY")

	resp, err := http.PostForm(endpoint + "/message?token=" + token, url.Values{"message": {message}, "title": {title}, "priority": {priority}})
	if resp != nil {
		resp.Body.Close()
	}
        if err != nil {
		log.Fatalln(err)
	}
}

Pour l’utiliser voici le step a mettre dans le pipeline .drone.yml. A noter que j’utlise les secret Drone.

- name: gotify
  image: fredix/arm64v8-alpine-drone-gotify
  settings:
    gotifytoken:
      from_secret: plugin_gotifytoken
    gotifyendpoint:
      from_secret: plugin_gotifyendpoint
    gotifytitle:
      from_secret: plugin_gotifytitle
    gotifypriority:
      from_secret: plugin_gotifypriority
    message: >
      {{#success build.status}}
        build {{build.number}} succeeded on {{repo.name}}. Good job {{build.author}}  {{build.link}}
      {{else}}
        build {{build.number}} failed on {{repo.name}}. Fix me please {{build.author}}  {{build.link}}
      {{/success}}
  when:
    status: [ success, failure ]

A savoir, au risque de perdre du temps, que Drone passe ces variables d’environnement au conteneur en ajoutant PLUGIN_. Dans le .drone.yml il ne faut donc pas mettre PLUGIN_GOTIFYTOKEN mais gotifytoken (Drone semble insensible à la casse).

Le problème de ce code est que l’on va recevoir la notification de manière brute. En effet le message est un template et il ne sera pas interprété, on va donc recevoir :

  {{#success build.status}}
    build {{build.number}} succeeded on {{repo.name}}. Good job {{build.author}}  {{build.link}}
  {{else}}
    build {{build.number}} failed on {{repo.name}}. Fix me please {{build.author}}  {{build.link}}
  {{/success}}

ce qui est assez inutile.. J’ai ajouté du code du plugin google chat pour que le template soit interprété. Après un déploiement on reçoit une jolie notification sur l’interface web et le smartphone.

gotify_3.png

Cet outil ouvre toutes sortes de perspectives comme des alertes de monitoring ou l’envoi de messages depuis des rapsberry pi.

Sources

Installer un serveur de notifications push Gotify
Deploying A Self-Hosted Portable Notification Service