december 2010 Archieven
Grafische gebruikersinteractie vanuit een script.
Geplaatst door Martijn Brekhof op 2010-12-31 13:55:31 | Permanente link | Categorie: Systeembeheer, Tips and Tricks | Reacties: 0
Een goede systeembeheerder maakt scripts. Scripts om zoveel mogelijk van z'n taken te automatiseren. Dat is fijn want dan kan de systeembeheerder zich namelijk met nuttiger dingen bezig houden.
Soms is echter een taak niet volledig te automatiseren en is er gebruikersinteractie nodig. Nu kan dat natuurlijk via een tekstuele interface en soms is dat ook de enige mogelijkheid. Maar wanneer je in een grafische omgeving werkt dan vind ik zo'n tekstuele interface toch wel een beetje oubollig en mis ik bijvoorbeeld de mogelijkheid om notificaties via de desktop naar de gebruiker te sturen.
Een voorbeeld van een script waarbij grafische gebruikersinteractie erg wenselijk is, is het backupscript dat ik gebruik om laptops te backuppen op een externe USB harddisk. Gebruikers moeten zelf voor de backup de externe harddisk aansluiten. De backup-procedure start dan automatisch maar het tijdig aansluiten van de externe harddisk vergeten ze natuurlijk. Dus ze moeten hierop gewezen worden. Ik gebruik een script dat controleert hoe lang het geleden is dat er een backup is gemaakt. Als dat langer dan zoveel dagen geleden is dan moet de gebruiker hier een melding van krijgen als hij is ingelogd op zijn systeem.
De tool die ik voor de grafische gebruikersinteractie gebruik is Zenity. Er zijn alternatieven, maar zenity integreert nu eenmaal erg goed met de GNOME of KDE desktop omgeving. Zenity heeft een scala aan opties, zie de manpage voor een overzicht. Voor mijn backup-oplossing heb ik er maar een paar nodig en zal ik wat voorbeelden geven hoe ik in bepaalde situaties zenity gebruik voor de gebruikersinteractie.
- Bij problemen moet de gebruiker op de hoogte worden gesteld en eventueel worden verzocht het probleem te verhelpen. Bijvoorbeeld wanneer de harddisk niet toegankelijk is. Dit kan met zenity als volgt:
zenity --question --title="Backupdisk niet toegankelijk" \
--text='De backupdisk is niet toegankelijk.
Koppel de disk en klik vervolgens op "Ga door" om verder te gaan.' \
--cancel-label='Stoppen' --ok-label='Ga door'
Op basis van de exit-code kunnen we dan achterhalen wat de gebruiker heeft geantwoord. Exitcode 1 voor "Stoppen" en 0 voor "Ga door".
- Het script zal ook weleens een notificatie moeten kunnen sturen naar de gebruiker. Bijvoorbeeld wanneer de backup klaar is. Het volgende zal de notificatie in het panel van de desktop laten zien:
zenity --notification --window-icon=/usr/share/pixmaps/gnome-note.png \
--text "De backup is klaar. U mag de backupdisk nu ontkoppelen"
Ik vind dit zelf echter onvoldoende opvallen en een wat meer in het oog springende oplossing is de volgende:
zenity --info --text "De backup is klaar. U mag de backupdisk nu ontkoppelen"
Dit zal een notificatie midden op het scherm tonen. Backups zijn nou eenmaal belangrijk.
- Tijdens het maken van de backup wil ik graag weten wat de vorderingen zijn.
Hier heeft zenity een mooie optie voor genaamd
--progress. Je dient dan via de standard input het percentage aan te geven en zenity zal dan de progression-bar netjes aanpassen. Een voorbeeld van het gebruik is als volgt:
for i in $(seq 1 100)
do
echo "${i}"
sleep 1
done | zenity --percentage=0 --progress --title "Backup wordt gemaakt" \
--text='Backup is in gang gezet.\nNiet de disk ontkoppelen tijdens het \
backup proces!'
Nadeel is dat het niet altijd mogelijk is om de progressie-bar netjes te updaten tijdens de backup-procedure.
Wanneer je de bestanden die zijn gekopieerd in een lijst wilt zien, kun je de --list
optie gebruiken als volgt:
zenity --list --title "Backup wordt gemaakt" --text='Backup is in gang gezet.
Niet de disk ontkoppelen tijdens het backup proces!' --column "Files" < /tmp/gebackupt
Hierbij moet je vervolgens ervoor zorgen dat het bestand /tmp/gebackupt steeds
de actuele lijst met bestanden die zijn gebackupt bevat. Zenity leest de
updates dan steeds in en toont deze dan in een grafisch scherm. Het scherm
heeft vervolgens een Cancel en OK knop. Ook hier kunnen we dan weer op basis
van de exitcode achterhalen welke knop de gebruiker heeft ingedrukt.
Volgende keer zal ik laten zien hoe ik zenity in mijn backup-script toepas.
D-Bus en Python
Geplaatst door Martijn Brekhof op 2010-12-08 17:21:26 | Permanente link | Categorie: Programmeren | Reacties: 0
In een vorige blog heb ik wat verteld over de D-Bus. Ik zal nu laten zien hoe makkelijk je met python een script kan maken om gebruik te maken van de D-Bus. Dit script luistert naar het signaal "StateChanged" van de NetworkManager en zal vervolgens programma's opstarten of afsluiten.
Het script ziet er als volgt uit.
1 #!/usr/bin/env python
2 import dbus, gobject, subprocess, shlex
3 from dbus.mainloop.glib import DBusGMainLoop
4
5 programs = [
6 ['startonce', 'empathy -h'],
7 ['startandstop', 'evolution']
8 ]
9
10 def start_programs(state):
11 if state == 4:
12 for program in programs[:]:
13 if program[0] == 'startandstop' and len(program) > 2:
14 program[2].terminate()
15 program.remove(program[2])
16 elif state == 3:
17 for program in programs[:]:
18 if not (program[0] == 'startonce' and len(program) > 2):
19 args = shlex.split(program[1])
20 p = subprocess.Popen(args)
21 program.append(p)
22
23 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
24 bus = dbus.SystemBus()
25 bus.add_signal_receiver(start_programs, dbus_interface="org.freedesktop.NetworkManager", signal_name="StateChanged")
26
27 loop = gobject.MainLoop()
28 loop.run()
De regelnummering aan het begin van elke regel moet je weglaten en heb ik toegevoegd om duidelijk te kunnen verwijzen naar bepaalde regels in het script.
We gebruiken de glib python binding om D-Bus ondersteuning te verkrijgen. Op
regel 23 gebruiken we DBusGMainLoop om gebruik te maken van de GLib
mainloop.
Vervolgens voegen we op regel 25 een ontvanger toe voor het signaal
"StateChanged". De mainloop zal er dan voor zorgen dat wanneer dit signaal
binnenkomt de functie start_programs wordt aangeroepen.
De mainloop wordt trouwens pas werkelijk opgestart in regel 28.
Op regels 5 tot en met 8 wordt een lijst gedefinieerd genaamd programs.
Deze lijst bevat de programma's die moeten worden opgestart. Sommige
programma's willen we alleen opstarten wanneer we een netwerk-connectie
hebben. Andere willen we ook afsluiten als de netwerk-connectie wegvalt.
De lijst programs bestaat hiervoor uit elementen die op hun beurt ook
weer lijsten zijn maar dan met 2 elementen. Dit noemen we ook wel een 2-tupel.
Het eerste element geeft aan of het programma bij een netwerkverbinding
eenmaal moet worden opgestart en niet moet worden afgesloten
(startonce) of dat het telkens moet worden opgestart en weer moet worden
afgesloten als de
netwerkverbinding wordt verbroken (startandstop).
De functie start_programs wordt gedefinieerd op regels 10 tot en met 21.
Als parameter wordt de status meegegeven die is ontvangen van het signaal
"StateChanged" van de D-Bus interface "org.freedesktop.NetworkManager".
Als de status gelijk is aan 3 worden de programma's in de lijst
programs doorlopen. Alle programma's die niet als startonce staan
gedefinieerd of nog niet zijn opgestart worden dan gestart op regel 20.
Het procesnummer (PID) wordt vervolgens toegevoegd aan de 2-tupel (waardoor het
een 3-tupel wordt).
Als de status gelijk is aan 4 worden de programma's in de lijst programs die
een procesnummer hebben én zijn gedefinieerd als startandstop
afgesloten door er het "terminate" signaal naar toe te sturen (regel 14). Vervolgens
wordt het procesnummer uit de lijst gehaald (regel 15) waardoor het weer zal worden
opgestart als de functie start_programs wordt aangeroepen met status gelijk
aan 3 (regels 17 tot en met 21).
