Pozadie
V jednej zdravotníckej organizácii implementovali riešenia založené na PACS serveroch Orthanc a DICOM klientovi Radiant. Počas nastavenia sme zistili, že každý DICOM klient musí byť v PACS serveroch opísaný nasledovne:
- Meno klienta
- AE-názov (musí byť jedinečný)
- TCP port, ktorý sa automaticky otvára na strane klienta a prijíma DICOM vyšetrenia z PACS servera (t.j. server ich akoby posiela k klientovi - iniciujúc spojenie prvý)
- IP adresa
Po nastavení Radiant klientov sme dostali nasledujúce informácie na zamyslenie – u každého klienta nastavenie softvéru s uvedenými parametrami viedlo k vyplneniu súboru pacs.xml, ktorý sa nachádzal v profilu používateľa (cesta: %APPDATA%RadiantViewerpacs.xml). Pri tom sa konfigurácia jedného klienta od druhej líšila minimálne dvoma parametrami (AE-názov bol u všetkých iný, a port bol väčšinou rovnaký, okrem terminálnych klientov, pracujúcich na tom istom serveri – tam porty bolo tiež potrebné priraďovať rôzne).
Príklad súboru pacs.xml podľa :
Približne pol roka všetko fungovalo dobre, systém sa rozbehol…a potom sa k nám dostali „podvodné kamene»:
- Musíme zaviesť do prevádzky niekoľko nových PACS serverov, ktoré nahradia staré (kde začalo dochádzať miesto na diskoch). PACS servery sú vo virtuálnych strojoch, ale o tom nehovoríme;
- Musíme nejakým spôsobom centralizovane zmeniť jedinečné konfigurácie (s dvoma odlišnými parametrami) na 200 strojoch (ich počet sa pravidelne zvyšoval);
- Zohľadňujúc tempo rastu objemov vyšetrení, riešenie musí byť nie jednorazové, ale replikovateľné a pravidelné (napríklad raz za 3-5 mesiacov).
Riešenie je nižšie.
Výber nástrojov na riešenie úlohy
Na začiatku sme sa snažili nájsť nejaké riešenie, ktoré by na strane klienta menilo súbor pacs.xml a zavádzalo do neho zmeny v zozname PACS serverov, bez dotykania nastavení AE-názvu a TCP portu. Windows klienti v tej dobe boli na báze Windows XP aj Windows 7 - preto boli pokusy napísať niečo na báze VBScript. Ale bohužiaľ – zvládnuť takú úlohu sa nepodarilo, vzhľadom na úplnú absenciu skúseností so zložitým a komplexným kódovaním v tomto jazyku. Pokusy o nájdenie a prepísanie taktiež nepriniesli úspech (tu treba poznamenať, že v hlave už bol iný plán, takže som sa s VBScript už viac ako 3-4 hodiny netrápil).
Nakoniec som sa zastavil pri nasledujúcom riešení:
- Zbierať skupinovou politikou všetky súbory pacs.xml na jednom serveri v sieťovom zdroji;
- Zmeniť súbory hromadne (máme už skúsenosti s riešením takýchto úloh – pomocou Perlu);
- Tiež pomocou skupinových politík aktualizovať nastavenia klientov.
Zber súborov pomocou skupinovej politiky
Najjednoduchšia časť – pri prihlásení klienta do svojho profilu sa s jeho oprávneniami vykoná určitý .bat súbor, v ktorom je uvedené:
echo off
If exist %APPDATA%RadiantViewerpacs.xml copy %APPDATA%RadiantViewerpacs.xml srv.test.localpconfigs$pacs-%COMPUTERNAME%-%USERNAME%.xml
Takže na serveri v skrytom zdroji sa budú hromadiť súbory pacs.xml, v názve ktorých je informácia, z akého počítača a od akého používateľa bol skopírovaný tento konfigurák.
Najťažšie bolo čakať, kedy sa táto politika vykoná u všetkých používateľov.
Zmena konfigurácií pomocou skriptu Perl
Budeme potrebovať pod Windows od spoločnosti ActiveState, ako aj modul XML::Writer, ktorý môžeme nainštalovať pomocou príkazu ppm install XML-Writer.
Skript sa ukázal byť dosť jednoduchý:
use XML::Writer;
# Otvoríme priečinok s reportmi, spracujeme zoznam (odstránime zbytočné):
$report_dir = "C:Perl64WORKPACS-xml3";
opendir(DIR, "$report_dir") or die "Nemôžem otvoriť priečinok s reportmi!";
@report_files = readdir DIR;
shift (@report_files); # odstránime bodku z prvkov poľa (.)
shift (@report_files); # odstránime dve bodky z prvkov poľa (..)
# print "@report_files";
closedir(DIR);
# Začneme spracovávať súbory - jeden po druhom. Potrebujeme uložiť parameter AET a číslo portu do premenných.
foreach $analiz_file (@report_files)
{
$full_path_to_file="C:Perl64WORKPACS-xml3".$analiz_file;
open (INFO, $full_path_to_file);
while ($line = )
{
# Premenné $aet a $port obsahujú jedinečné dáta pre každý XML súbor:
my ($other1, $aet, $other2, $port, $other3) = split "/", $line, 5;
# Ak natrafíme na riadok listener - tak sme dorazili na potrebný riadok a môžeme vytvárať nový XML:
if ($other1 =~ 'listener')
{
# Vytvárame nový XML s potrebnými poľami a údajmi:
my $writer = XML::Writer->new(OUTPUT => 'self', DATA_MODE => 1, DATA_INDENT => 2, );
$writer->xmlDecl('utf-8');
$writer->startTag('pacs');
$writer->startTag('listener', ae => $aet, port => $port);
$writer->endTag();
$writer->startTag('hosts');
$writer->startTag('host', name => 'MRT', ae => 'ORTHANC', ip => 'XX.YY.214.17', ts => '1.2.840.10008.1.2.1', port => '4242', maxassoc => '1', allpres => '0', search => '1', protocol => '1', searchcharset => '', wildcards => '3', carets => '0');
$writer->endTag();
$writer->startTag('host', name => 'KT', ae => 'ORTHANC2', ip => 'XX.YY.215.253', ts => '1.2.840.10008.1.2.1', port => '4242', maxassoc => '1', allpres => '0', search => '1', protocol => '1', searchcharset => '', wildcards => '3', carets => '0');
$writer->endTag();
$writer->startTag('host', name => 'R', ae => 'ORTHANC3', ip => 'XX.YY.215.252', ts => '1.2.840.10008.1.2.1', port => '4242', maxassoc => '1', allpres => '0', search => '1', protocol => '1', searchcharset => '', wildcards => '3', carets => '0');
$writer->endTag();
$writer->startTag('host', name => 'KT-20180501-20180831', ae => 'ORTHANC4', ip => 'XX.YY.215.251', ts => '1.2.840.10008.1.2.1', port => '4242', maxassoc => '1', allpres => '0', search => '1', protocol => '1', searchcharset => '', wildcards => '3', carets => '0');
$writer->endTag();
$writer->startTag('host', name => 'KT-20180901-20181130', ae => 'ORTHANC5', ip => 'XX.YY.215.250', ts => '1.2.840.10008.1.2.1', port => '4242', maxassoc => '1', allpres => '0', search => '1', protocol => '1', searchcharset => '', wildcards => '3', carets => '0');
$writer->endTag();
$writer->endTag('hosts');
$writer->startTag('presets');
$writer->endTag();
$writer->startTag('lastsearch', dt => '4', mfid => '1048592');
$writer->endTag();
$writer->endTag('pacs');
# Vložíme hotový XML do premennej:
my $xml = $writer->end();
# Pripravíme súbor na prepísanie:
$rewritexml = $full_path_to_file;
# Prepíšeme XML súbory novými dátami:
open (NEWXML, "> $rewritexml");
print NEWXML $xml;
close (NEWXML);
}
}
}
Princíp jeho fungovania:
- Otvárame katalóg, v ktorom máme zhromaždené konfigurácie pacs.xml od klientov a vkladáme zoznam súborov do poľa skalarov (@report_files);
- V cykle spracovávame jeden súbor po druhom a čítame ho riadok po riadku;
- S pomocou split delíme každý riadok na 5 častí, pričom používame úvodzovky ako oddeľovač;
- Nájdenie riadku so slovom listener a uloženie unikátnych údajov pre každý súbor do dvoch premenných (AE-meno klienta a číslo TCP-portu);
- Potom jednoducho vytvoríme nový XML-súbor, zapíšeme do neho unikátne parametre a následne vložíme potrebný počet PACS-serverov so svojimi parametrami – t.j. to, kvôli čomu to všetko vlastne robíme)
- Prepisujeme nový XML-súbor na miesto starého.
Treba poznamenať, že v skutočnosti tento skript nepoužívam úplne automaticky – vlastne kopírujem zhromaždené konfigurácie do samostatného katalógu a potom spúšťam skript, pričom ich všetky naraz mením. Potom vykonávam selektívnu kontrolu – a konfigurácie môžem rozdistribuovať späť na stroje.
Distribúcia upravených pacs.xml súborov medzi klientmi
Najjednoduchšie, čo ma napadlo – vykonať zmeny v už fungujúcom .bat súbore, ktorý zhromažďuje konfigurácie od klientov a pridať riadok:
If exist %APPDATA%RadiantViewerpacs.xml copy /Y srv.test.localpconfigsnew$pacs-%COMPUTERNAME%-%USERNAME%.xml %APPDATA%RadiantViewerpacs.xml
Konečný .bat súbor vyzerá takto:
@echo off
If exist %APPDATA%RadiantViewerpacs.xml copy %APPDATA%RadiantViewerpacs.xml srv.test.localpconfigs$pacs-%COMPUTERNAME%-%USERNAME%.xml
If exist %APPDATA%RadiantViewerpacs.xml copy /Y srv.test.localpconfigsnew$pacs-%COMPUTERNAME%-%USERNAME%.xml %APPDATA%RadiantViewerpacs.xml
Záver
Takéto "na kolene" riešenie. Vyskúšali sme ho už dvakrát (v septembri 2018 a vo februári 2019), zatiaľ letí normálne. Samozrejme, neaktualizuje 100% klientov, ale blízko k tejto hodnote – zvyšných dokončujeme na diaľku. Skript sa .
Zdroj: habr.com
