Synology erreur de lancement script python au démarrage du nas

Ochidoris

Padawan
4 Mars 2021
91
22
8
Bonjour à tous,
J'ai un petit soucis de script.
J'utilise mon nas comme serveur seedbox (sonarr, radarr, jackett, emby, etc...). Mon serveur plex est installé sur une nvidia shield.
Cette configuration a 2 inconvénients :
- la 1ere : Les films mettent plusieurs secondes à se lancer. Résolution : passer en SMB1.
- la 2eme : les bibliothèques ne se mettent pas à jour automatiquement. Résolution via un script python.
Le script fonctionne bien et détecte immédiatement les changements dans les bibliothèques.
Au démarrage, le script créé deux fichiers (un "plex inotify.log" et un "plex inotify.pid") et ce sont ces fichiers qui me posent problème.
Si je redémarre le nas, ce script ne se lance pas malgré que je l'ai configuré dans le planificateur de tache. Idem si je le lance en manuel, rien ne se passe... Il faut que j'efface les deux fichiers sus-cités avant de relancer le script.
Bref, ce n'est pas terrible.
Est-ce que l'on peut programmer la suppression de ces deux fichiers avant l’extinction du nas ? Ou existe-t-il un dossier (sorte de cache) qui s'effacerait avant l'extinction ou, éventuellement, en programmer 1 ?
Merci de votre aide,
Cdt.
 
Salut,
Pourquoi ne pas lancer une commande qui supprime les fichiers ( s'ils existent ) avant de lancer de le script ?

SMB1 est plein de faille de sécu, c'est clairement pas une solution malheuresement :?
 
Salut Evtok,
oui, les effacés au lancement juste avant le démarrage du script ou les effacés à l'extinction de l'appareil.
La finalité est que je n'ai plus rien à faire, que tout soit automatisé. Malheureusement, je n'y connais pas grand chose en script, je ne fais qu'appliquer ce que je trouve sur les tutos.
Malheureusement, le SMB1 est la seule solution que j'ai trouvé. Je m'étonnais que le lancement des films soient si long alors j'ai recherché et, visiblement, c'était "normal", il n'y avait que cela de proposer pour corriger ce "bug". Je vais chercher à nouveau, cela a peut-être évolué depuis mes dernières recherches.
Encore merci.
 
Si tu utilise Discord, pour les questions en rapport avec Plex, n'hesite pas a venir ici : https://www.forum-nas.fr/viewtopic.php?f=3&t=14024

En Bash cela donne :
Code:
if [ -f "/mon/dossier/plex inotify.log" ];then
echo "Le fichier existe";
fi

En Python:
Code:
def checkFileExistance(filePath):
    try:
        with open(filePath, 'r') as f:
            return True
    except FileNotFoundError as e:
        return False
    except IOError as e:
        return False
 
Merci Evtok,
Entre temps, j'ai trouvé et testé cette ligne de commande dans le planificateur de tache :
find /volume1/docker/script/temp/plex-inotify.pid -delete
find /volume1/docker/script/temp/plex-inotify.log -delete
Eh bien, ça fonctionne, il s'efface à l'arrêt du nas !
L'appareil redémarre, lance le script et re-crée les fichiers et... ça ne fonctionne pas...
J'efface manuellement les fichiers, lance le script depuis le planificateur (donc le même) et ça fonctionne. Bref, j'y comprenais pas grand chose mais là, ça défit carrément ma logique.
Encore plus étrange, je désactive le lancement automatique du script, je reboote le nas, mes fichiers s'effacent, je vais dans le planificateur de tache, je fais exécuter le script et là... ça marche !
Bref, tout cela dépasse ma simple compréhension.
J'aimerais testé le lancement automatique différé de quelques minutes, est-ce possible ?
Actuellement, j'utilise cette ligne :
python3 /volume1/docker/script/plex-inotify.py
Merci encore.
 
Ah ok, tu vois mon niveau maintenant !! ;p
voici le script en entier. Je le met où stp ?


Code:
# PLEX NOTIFIER SCRIPT v1.4
# Written by Talisto: https://forums.plex.tv/profile/talisto
# Modified heavily from https://codesourcery.wordpress.com/2012/11/29/more-on-the-synology-nas-automatically-indexing-new-files/

###################################################
# MODIFY VARIABLES HERE
###################################################

# Plex Server IP or hostname
plex_server_host = '192.168.1.90'

# Plex Server port
plex_server_port = 32400

# Plex account token; only required if your primary account has a PIN enabled,
# or if you have multiple users.  Instructions how to get your token:
# https://support.plex.tv/hc/en-us/articles/204059436-Finding-your-account-token-X-Plex-Token
plex_account_token = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'

# Map the fileserver's local paths to their associated Plex Media Server library names
path_maps = {
    '/volumeUSB1/usbshare/multimedias/plex/series animees': 'Series Animees',
    '/volumeUSB1/usbshare/multimedias/plex/series tv': 'Series TV',
    '/volumeUSB1/usbshare/multimedias/plex/films': 'Films',
    '/volumeUSB1/usbshare/multimedias/plex/films animation': 'Animations',
    '/volumeUSB1/usbshare/multimedias/plex/maxence/films':'Films Maxence',
    '/volumeUSB1/usbshare/multimedias/plex/maxence/series':'Series Maxence',
}

# Allowed file extensions
allowed_exts = [
    'jpg', 'jpeg', 'png', 'gif', 'bmp', 'tiff',
    'mp3', 'flac', 'aac', 'wma', 'ogg', 'ogv', 'wav', 'wma', 'aiff',
    'mpg', 'mp4', 'avi', 'mkv', 'm4a', 'mov', 'wmv', 'm2v', 'm4v', 'vob'
]

# Log file
log_file_path = '/volume1/docker/script/temp/plex-inotify.log'

# PID file
pid_file_path = '/volume1/docker/script/temp/plex-inotify.pid'

# Daemonize (run in the background) or not
daemonize = True

# connect to PMS using HTTPS instead of HTTP
# NOTE: The HTTPS connection does not validate the SSL certificate!!
secure_connection = False

###################################################
# YOU SHOULDN'T NEED TO TOUCH ANYTHING BELOW HERE
###################################################

import pyinotify
import sys
import os.path
from subprocess import call
import signal
import fnmatch
import urllib.request
import ssl
import xml.etree.ElementTree as ET
import json

###################################################
# CLASSES / FUNCTIONS
###################################################

class EventHandler(pyinotify.ProcessEvent):

    def __init__(self, host, port, protocol, token, libraries, allowed_exts):
        self.modified_files = set()
        self.plex_host = host
        self.plex_port = port
        self.plex_account_token = token
        self.protocol = protocol
        self.libraries = libraries
        self.allowed_exts = allowed_exts

    def process_IN_CREATE(self, event):
        self.process_path(event, 'CREATE')

    def process_IN_MOVED_TO(self, event):
        self.process_path(event, 'MOVED TO')

    def process_IN_MOVED_FROM(self, event):
        self.process_path(event, 'MOVED FROM')

    def process_IN_DELETE(self, event):
        self.process_path(event, 'DELETE')

    def process_IN_MODIFY(self, event):
        if self.is_allowed_path(event.pathname, event.dir):
            self.modified_files.add(event.pathname)

    def process_IN_CLOSE_WRITE(self, event):
        # ignore close_write unlesss the file has previously been modified.
        if (event.pathname in self.modified_files):
            self.process_path(event, 'WRITE')

    def process_path(self, event, type):
        if self.is_allowed_path(event.pathname, event.dir):
            log("Notification: %s (%s)" % (event.pathname, type))

            for path in list(self.libraries.keys()):
                if fnmatch.fnmatch(event.pathname, path + "/*"):
                    log("Found match: %s matches Plex section ID: %d" % (
                        event.pathname,
                        self.libraries[path]
                    ))
                    self.update_section(self.libraries[path])

            # Remove from list of modified files.
            try:
                self.modified_files.remove(event.pathname)
            except KeyError as err:
                # Don't care.
                pass
        else:
            log("%s is not an allowed path" % event.pathname)

    def update_section(self, section):
        log('Updating section ID %d' % (section))
        response = url_open("%s://%s:%d/library/sections/%d/refresh" % (
            self.protocol,
            self.plex_host,
            self.plex_port,
            section
        ), self.plex_account_token)

    def is_allowed_path(self, filename, is_dir):
        # Don't check the extension for directories
        if not is_dir:
            ext = os.path.splitext(filename)[1][1:].lower()
            if ext not in self.allowed_exts:
                return False
        if filename.find('@eaDir') > 0:
            return False
        return True

def log(text):
    if not daemonize:
        print(text)
    log_file.write(text + "\n")
    log_file.flush()

def signal_handler(signal, frame):
    log("Exiting")
    sys.exit(0)

# custom urlopen() function to bypass SSL certificate validation
def url_open(url, token):
    if token:
        req = urllib.request.Request(url + '?X-Plex-Token=' + token)
    else:
        req = urllib.request.Request(url)
    if url.startswith('https'):
        ctx = ssl.create_default_context()
        ctx.check_hostname = False
        ctx.verify_mode = ssl.CERT_NONE
        return urllib.request.urlopen(req, context=ctx)
    else:
        return urllib.request.urlopen(req)

###################################################
# MAIN PROGRAM STARTS HERE
###################################################

log_file = open(log_file_path, 'a')

watch_events = pyinotify.IN_CLOSE_WRITE \
    | pyinotify.IN_DELETE \
    | pyinotify.IN_CREATE \
    | pyinotify.IN_MOVED_TO \
    | pyinotify.IN_MOVED_FROM

signal.signal(signal.SIGTERM, signal_handler)

if secure_connection:
    protocol = 'https'
else:
    protocol = 'http'

libraries = {}
response = url_open(
    "%s://%s:%d/library/sections" % (
        protocol,
        plex_server_host,
        plex_server_port
    ),
    plex_account_token
)
tree = ET.fromstring(response.read().decode("utf-8"))
for directory in tree:
    for path, name in path_maps.items():
        if directory.attrib['title'] == name:
            libraries[path] = int(directory.attrib['key'])
log("Got Plex libraries: " + json.dumps(libraries))

handler = EventHandler(
    plex_server_host,
    plex_server_port,
    protocol,
    plex_account_token,
    libraries,
    allowed_exts
)
wm = pyinotify.WatchManager()
notifier = pyinotify.Notifier(wm, handler)

log('Adding directories to inotify watch')

wdd = wm.add_watch(
    list(libraries.keys()),
    watch_events,
    rec=True,
    auto_add=True
)

log('Starting loop')

try:
    notifier.loop(daemonize=daemonize, pid_file=pid_file_path)
except pyinotify.NotifierError as err:
    print(err, file=sys.stderr)
 
Bon bah, je n'ai pas pu attendre et j'ai déjà testé et ça fonctionne !
C'est parfait maintenant.
Un grand merci à toi !
Si je peux abuser, j'ai à peu prés le même problème avec un container. Peut-on faire la même chose avec un container ?
Je m'explique, j'ai Qbittorrent associé avec un reseau vpn mais lorsque je démarre, je pense qu'ils se lancent en même temps, du coup qbittorrent reste à l'arrêt et il faut que je le lance depuis le stack de portainer.
cdt
 
Ochidoris a dit:
Bon bah, je n'ai pas pu attendre et j'ai déjà testé et ça fonctionne !
Super :)

Ochidoris a dit:
Si je peux abuser, j'ai à peu prés le même problème avec un container. Peut-on faire la même chose avec un container ?
Je m'explique, j'ai Qbittorrent associé avec un reseau vpn mais lorsque je démarre, je pense qu'ils se lancent en même temps, du coup qbittorrent reste à l'arrêt et il faut que je le lance depuis le stack de portainer.

Un delai sur un conteneur, je ne pense pas, en tout cas, cela ne me parle pas.
Par contre, pour ne pas avoir ce soucis, il te faut dire a ton conteneur Qbittorrent qu'il dépend du conteneur vpn, et donc qu'il ne doit pas démarrer sans lui !
En docker-compose cela se résume comme ceci :

Code:
depends_on:
      - vpn

* ou vpn est le nom du conteneur vpn

J'utilise autoheal pour surveiller mes conteneurs : https://github.com/willfarrell/docker-autoheal
J'ai fait un tuto ici sur autoheal : https://www.forum-nas.fr/viewtopic.php?f=90&t=16019
Je le fait surveiller mon conteneur vpn, il le reboot en cas de soucis, et surveille aussi les conteneurs qui sont lié en cas de soucis il reboot.
 
Ah oui, en effet ça me semble être une bonne solution. Je testerai tout ça à l'occasion.
Je viens de m'apercevoir que j'ai utilisé ton docker compose, trouvé sur un autre forum, pour ma solution Qbittorrent à travers un vpn.
Donc encore un TRÈS grand merci pour tout ton taff.
Je n'hésiterai pas à revenir vers toi en cas de soucis.
Bonne nuit. Cdt.
 
Bonjour,
Malheureusement, ça ne fonctionne toujours pas, même avec "autoheal".
J'ai utilisé ton "docker-compose" Qbittorrent que voici :

Code:
version: "3.2"

services: 
  vpn:
    image: dperson/openvpn-client:latest
    container_name: vpn
    restart: unless-stopped
    cap_add:
     - NET_ADMIN
    sysctls:
     - net.ipv6.conf.all.disable_ipv6=0
    security_opt:
     - label:disable
    environment:
     - PUID=1000
     - PGID=100
     - TZ=Europe/Paris
    networks:
     - vpn-network
    dns:
     - 84.200.69.80
     - 8.8.8.8
     - 9.9.9.9
    ports:
     - 8586:8586 #WebUI qbit
    devices:
     - /dev/net/tun:/dev/net/tun
    volumes:
     - /volume1/docker/vpn/config:/vpn
    command: '-f "" -r 192.168.0.0/24'
    healthcheck:
      test: ["CMD", "curl", "-Ss", "ifconfig.co"]
      interval: 60s
      timeout: 15s

  qbittorrent:
    image: ghcr.io/linuxserver/qbittorrent
    container_name: qbittorrent
    labels:
     - com.centurylinklabs.watchtower.enable=true
    depends_on:
     - vpn
    network_mode: "service:vpn"
    environment:
     - PUID=1000
     - PGID=100
     - TZ=Europe/Paris
     - WEBUI_PORT=8586
    volumes:
     - /volume1/docker/qbittorrent/config:/config
     - /volume1/docker/qbittorrent/downloads:/downloads
    restart: unless-stopped

networks:
  vpn-network:
    external:
      name: vpn-network

Au démarrage du nas, le container vpn se lance correctement tandis que qbittorrent est "stopped".
Il faut que je le lance manuellement via portainer car dans docker, j'ai un message d'erreur :"un container doit au moins rejoindre un reseau".
Autoheal me semblait parfait mais je pense qu'il relance un container qui s'est arrêté alors que j'imagine que le mien n'a jamais démarré...
Est-ce que tu aurais une suggestion ? J'ai entré autoheal en valeur "true" via labels de portainer et l'ai installé avec docker-compose.
Ou peut-être existe-t-il d'autres solutions ? Un script qui relance le container ?
Il ne me reste plus que ça, même si ce n'est qu'un détail, pour que tout le nas fonctionne aux oignons de manière autonome. :D
Encore merci
 
Ochidoris a dit:
Est-ce que tu aurais une suggestion ? J'ai entré autoheal en valeur "true" via labels de portainer et l'ai installé avec docker-compose.
Ou peut-être existe-t-il d'autres solutions ? Un script qui relance le container ?
Il ne me reste plus que ça, même si ce n'est qu'un détail, pour que tout le nas fonctionne aux oignons de manière autonome. :D
Encore merci

Salut,
Il est normal que cela ne fonctionne pas.
Plusieurs choses :

- Si tu install des conteneurs via docker-compose, ne les modifie pas avec Portainer en plus des soucis de compatibilité de certains arguments, les modifications ne seront pas persistantes, au moment ou tu re-lancera tes conteneurs via docker-compose les modifications faites avec Portainer seront perdues.

- Pour qu'un conteneur puisse être surveiller via autoheal, celui ci doit inclure 2 choses !

En premier : un "healcheck", il peut etre dans le "script" du conteneur, ou si ce n'est pas le cas, on peu en "créer" un a la création du conteneur. C'est le cas pour el conteneur vpn, si tu regarde la fin du compose openvpn, il y a une section healthcheck. Dans le cas du conteneur vpn, il va contacter le site ifconfig.co toute les minutes pour vérifier la bonne connexion du vpn.
Le conteneur qbittorrent ne possède pas de healcheck, tu peu facilement le voir sur Portainer, un conteneur avec un healtcheck quand il sera en "vie" indiquera "healtly" alors qu'un conteneur en fonction mais sans healcheck indiquera "running" tout simplement :
Pa9MJKm.png


Alors comment faire pour qbittorent ? Tout simplement en lui rajoutant un healcheck que autoheal va pouvoir surveiller.

Code:
    healthcheck:
     test: ["CMD-SHELL", "curl --fail http://172.22.0.1:8586/ || exit 1"]
     interval: 1m30s
     timeout: 10s
     retries: 3

Ici je surveille que le port 8586 ( port par defaut du qbit répond bien sur l'ip de la passerelle du reseau docker. Attention tu n'a peut etre pas la meme ip de passerelle, pour la connaitre, vu que tu utilise Portainer, tu va dans Network, et tu regarde l'IPV4 IPAM Gateway associé a ton reseau vpn-network.
T7UNwh6.png


En deuxième : Si tu as suivi mon tuto pour autoheal alors il te faut rajouter le label autoheal au conteneur. Pour cela tu dois modifier ton docker compose pour rajouter le label autoheal=true , paragraphe 1.b



Ton compose devrait donc plutot resembler a ceci :
Code:
version: "3.2"

services: 
  vpn:
    image: dperson/openvpn-client:latest
    container_name: vpn
    restart: unless-stopped
    labels:
     - autoheal=true
    cap_add:
     - NET_ADMIN
    sysctls:
     - net.ipv6.conf.all.disable_ipv6=0
    security_opt:
     - label:disable
    environment:
     - PUID=1000
     - PGID=100
     - TZ=Europe/Paris
    networks:
     - vpn-network
    dns:
     - 84.200.69.80
     - 8.8.8.8
     - 9.9.9.9
    ports:
     - 8586:8586 #WebUI qbit
    devices:
     - /dev/net/tun:/dev/net/tun
    volumes:
     - /volume1/docker/vpn/config:/vpn
    command: '-f "" -r 192.168.0.0/24'
    healthcheck:
      test: ["CMD", "curl", "-Ss", "ifconfig.co"]
      interval: 60s
      timeout: 15s

  qbittorrent:
    image: ghcr.io/linuxserver/qbittorrent
    container_name: qbittorrent
    labels:
     - autoheal=true
     - com.centurylinklabs.watchtower.enable=true
    depends_on:
     - vpn
    network_mode: "service:vpn"
    environment:
     - PUID=1000
     - PGID=100
     - TZ=Europe/Paris
     - WEBUI_PORT=8586
    volumes:
     - /volume1/docker/qbittorrent/config:/config
     - /volume1/docker/qbittorrent/downloads:/downloads
    restart: unless-stopped
    healthcheck:
     test: ["CMD-SHELL", "curl --fail http://172.22.0.1:8586/ || exit 1"]
     interval: 1m30s
     timeout: 10s
     retries: 3

networks:
  vpn-network:
    external:
      name: vpn-network
 
Salut,
C'est vraiment sympa de partager ton savoir et de prendre le temps de bien m'expliquer.
Bon malgré tout, ça ne fonctionne pas.
Enfin oui et non, l'objectif que Qbittorrent se lance au démarrage du nas n'est pas atteint, le statut reste en rouge sur "Stopped" mais, une fois lancée manuellement, il passe en vert "healthy" après j'imagine que s'il y a un problème, il se relancera. Si je le stoppe manuellement, il repasse en "stopped" et ne se relance pas.
Dans le titre de ton tuto, tu précises bien :"Redémarrer automatiquement un conteneur Docker avec un statut unhealthy", je pense que tout est dit.
Utilises-tu en client torrent sous vpn avec ton nas ? Si oui, est-ce que ça se lance correctement au démarrage ?
Si c'est le cas, quelle est ta solution ?
J'ai tenté de scinder le docker-compose pour lancer un service vpn d'une part et le client torrent d'autre part mais je n'arrive pas à installer Qbittorrent.
J'ai alors installé, après avoir lancé le docker-compose du vpn, le container qbittorrent mais je n'arrive pas à rejoindre le vpn. Je sélectionne pourtant le réseau "vpn-network" mais c'est mon ip d'origine qui s'affiche.
Si tu as d'autres idées, je suis preneur sinon, tant pis, j'ai déjà gagné en connaissance et j'y vois plus clair. :plusun:
cdt
 
Ochidoris a dit:
Si oui, est-ce que ça se lance correctement au démarrage ?
Pour ma part, non, au démarrage du NAS cela ne fonctionne pas, pour une raison simple le TUN se lance trop tard, et le conteneur vpn a deja esayé de démarrer et ne re-exxaye pas apres l'erreur. Si je lance le script TUN trop tot au démarrage cela ne fonctionne pas non plus, j'ai donc réduit le délai, mais je ne sais pas si cela fonctionne car j'éteint mon NAS tres très rarement, meme en réalité jamais ... Par contre, le probleme que tu me décrit ne semble pas similaire au mien.
Si je comprend bien :
- Mon soucis, démarrage du conteneur vpn trop tôt par rapport a la création du TUN
- Ton soucis, le conteneur vpn démarre mais pas qbittorrent

Ochidoris a dit:
Si c'est le cas, quelle est ta solution ?
Ne jamais éteindre le NAS :lol:

Ochidoris a dit:
J'ai tenté de scinder le docker-compose pour lancer un service vpn d'une part et le client torrent d'autre part mais je n'arrive pas à installer Qbittorrent.
J'ai alors installé, après avoir lancé le docker-compose du vpn, le container qbittorrent mais je n'arrive pas à rejoindre le vpn. Je sélectionne pourtant le réseau "vpn-network" mais c'est mon ip d'origine qui s'affiche.
Si tu coupe le compose en deux, alors attention, pour qbittorrent ce n'est plus
Code:
network_mode: "service:vpn"
qu'il faut indiquer mais
Code:
network_mode: "container:vpn"
, quand tu précise "service" il va le chercher dans le même docker-compose.

Ochidoris a dit:
Si tu as d'autres idées, je suis preneur sinon, tant pis, j'ai déjà gagné en connaissance et j'y vois plus clair. :plusun:

C'est plutôt étrange qui ne repart pas tout seul, avec l'option
Code:
restart: unless-stopped
le conteneur doit vouloir rester en vie tout le temps, SAUF s'il a était stoppé ( manuellement ou automatiquement ), dans se cas, meme un redémarrage ne le réactive pas.
Tu peu aussi utiliser
Code:
restart: always
qui redémarre toujours le conteneur avec le deamon docker, meme si celui ci était arreté.

Plus d'info : https://docs.docker.com/config/containers/start-containers-automatically/
 
Bon bah rien ne semble fonctionner. Dans le log, ça indique que ça n'a pas pu se connecter au réseau...
C'est dommage parce que le VPN, lui, y arrive.
Dernière petite idée "de naïf", ne peut-on pas ajouter en tache, dans le planificateur, la réinstallation du docker-compose au démarrage comme on lancerait un script ?
une commande du genre : "docker-compose up -d /volume1/etc..."
Si ce n'est pas possible, j'abandonne là cette idée. :arrow:
Encore merci.
 
Etrange ton soucis :(
Ochidoris a dit:
Dernière petite idée "de naïf", ne peut-on pas ajouter en tache, dans le planificateur, la réinstallation du docker-compose au démarrage comme on lancerait un script ?
une commande du genre : "docker-compose up -d /volume1/etc..."

Si c'est possible, dans le planificateur, en root, tu execute :

Code:
sleep 90
docker-compose -f /volume1/docker/dossier/docker-compose.yml -p ma-stack up -d

90 est le temps en seconde a attendre avant l'execution
/volume1/docker/dossier/docker-compose.yml est le chemin absolu vers le docker-compose.yml
ma-stack est le nom que tu souhaite donner a l'ensemble de service ( pas defaut c'est le nom du dossier ou se trouve le fichier docker-compose.yml