Background
I en medicinsk organisation implementerede de løsninger baseret på PACS-servere Orthanc og DICOM-klienten Radiant. Ved opsætningen fandt vi ud af, at hver DICOM-klient skal beskrives i PACS-serverne som følger:
- Klientens navn
- AE-navn (skal være unikt)
- TCP-port, der automatisk åbnes på klientens side og modtager DICOM-undersøgelser fra PACS-serveren (dvs. serveren 'skubber' dem mod klienten – initierer forbindelsen først)
- IP-adresse
Efter opsætningen fik Radiant-klienterne følgende information til eftertanke – for hver klient førte indstillingen af softwaren med de ovenfor angivne parametre til udfyldelsen af filen pacs.xml, som lå i brugerens profil (sti: %APPDATA%RadiantViewerpacs.xml). Konfigurationen for én klient adskilte sig fra en anden med minimum to parametre (AE-navnet var forskelligt for alle, mens porten hovedsageligt var den samme, undtagen terminalklienter, der kørte på den samme server – der måtte også tildeles forskellige porte).
Eksempel på filen pacs.xml fra :
Omtrent et halvt år gik alt godt, systemet fungerede... og så kom 'undergrunds klipper»:
- Vi er nødt til at tage flere nye PACS-servere i brug, der skal erstatte de gamle (hvor der ikke var mere plads på harddiskene). PACS-servere i virtuelle maskiner, men det handler ikke om det;
- Vi skal på en eller anden måde centralt ændre de unikke konfigurationer (med to forskellige parametre) på 200 maskiner (deres antal voksede jævnligt);
- I betragtning af væksthastigheden af undersøgelsesvolumener skal løsningen ikke være engangs, men reproducerbar og regelmæssig (f.eks. én gang hver 3-5 måneder).
Løsningen er nedenfor.
Valg af værktøj til at løse opgaven
I starten var der forsøg på at finde en løsning, der på klientens side ændrede filen pacs.xml og foretog ændringer i listen over PACS-servere uden at røre ved indstillingerne for AE-navn og TCP-port. Windows-klienterne var på det tidspunkt baseret både på Windows XP og Windows 7 – derfor var der forsøg på at skrive noget i VBScript. Men desværre – jeg kunne ikke magte en sådan opgave, da jeg helt manglede erfaring i at skrive noget komplekst og komplekst på dette sprog. Forsøgene på at finde og omskrive blev heller ikke en succes (her skal det bemærkes, at der allerede var en anden plan i hovedet, så jeg nølede ikke med VBScript i mere end 3-4 timer).
I sidste ende besluttede jeg at gå med følgende løsning:
- Samle en gruppepolitik, der placerer alle pacs.xml-filer et sted på en server i netværksressourcen;
- Ændre filerne i samlet form (der er tidligere erfaring med at løse sådanne opgaver - ved hjælp af Perl);
- Opdater også klientindstillingerne ved hjælp af gruppepolitikker.
Indsamling af filer ved hjælp af gruppepolitikker
Den nemmeste del - når en klient logger ind i sin profil, kører han en .bat-fil, som indeholder:
echo off
If exist %APPDATA%RadiantViewerpacs.xml copy %APPDATA%RadiantViewerpacs.xml srv.test.localpconfigs$pacs-%COMPUTERNAME%-%USERNAME%.xml
På denne måde vil pacs.xml-filer samle sig på serveren i en skjult ressource, hvis navne indeholder information om, hvilken computer og hvilken bruger den pågældende konfiguration blev kopieret fra.
Det sværeste var at vente på, at denne politik trådte i kraft for alle brugere.
Ændring af konfigurationer med en Perl-script
Vi får brug for til Windows fra ActiveState, samt modulet XML::Writer, som kan installeres med kommandoen ppm install XML-Writer.
Selve scriptet viste sig at være ganske simpelt:
use XML::Writer;
# Åbner mappen med rapporter, behandler listen (fjerner unødvendige elementer):
$report_dir = "C:Perl64WORKPACS-xml3";
opendir(DIR, "$report_dir") or die "Kan ikke åbne mappen med rapporter!";
@report_files = readdir DIR;
shift (@report_files); # fjerner punktum fra arrayelementer (.)
shift (@report_files); # fjerner to punktummer fra arrayelementer (..)
# print "@report_files";
closedir(DIR);
# Begynder at behandle filer - en ad gangen. Man skal læse parameter AET og portnummer i variabler.
foreach $analiz_file (@report_files)
{
$full_path_to_file="C:Perl64WORKPACS-xml3".$analiz_file;
open (INFO, $full_path_to_file);
while ($line = )
{
# Variablerne $aet og $port indeholder unikke data for hver XML-fil:
my ($other1, $aet, $other2, $port, $other3) = split /"/, $line, 5;
# Hvis strengen listener findes - så har vi nået den ønskede linje og kan danne ny XML:
if ($other1 =~ 'listener')
{
# Danner ny XML med de nødvendige felter og data:
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');
# Placerer den færdige XML i en variabel:
my $xml = $writer->end();
# Forbereder filen til overskrivning:
$rewritexml = $full_path_to_file;
# Skriver XML-filer om med nye data:
open (NEWXML, "> $rewritexml");
print NEWXML $xml;
close (NEWXML);
}
}
}
Principen for dets arbejde:
- Vi åbner kataloget, der indeholder konfigurationer af pacs.xml fra kunderne, og placerer listen over filer i en skalar array (@report_files);
- I en løkke behandler vi én fil ad gangen og læser den linje for linje;
- Ved hjælp af split opdeler vi hver linje i 5 dele ved at bruge anførselstegn som separator;
- Vi finder linjen med ordet listener og placerer de unikke data (AE-kundens navn og nummeret på TCP-port) i to variabler, der er unikke for hver fil;
- Derefter opretter vi blot en ny XML-fil, skriver de unikke parametre ind, og indsætter det nødvendige antal PACS-servere med deres parametre - altså det, som hele dette tiltag drejer sig om)
- Vi overskriver den gamle XML-fil med den nye.
Det skal bemærkes, at jeg faktisk ikke bruger dette script helt automatisk – i stedet kopierer jeg de indsamlede konfigurationer til et separat katalog og kører derefter scriptet for at ændre dem alle på én gang. Herefter en stikprøvekontrol – og konfigurationerne kan deles tilbage til maskinerne.
Distribution af de ændrede pacs.xml-filer til kunderne
Det mest enkle, der kom til at tænke på – at foretage ændringer i den eksisterende .bat fil, der indsamler konfigurationerne fra kunderne, og tilføje linjen:
If exist %APPDATA%RadiantViewerpacs.xml copy /Y srv.test.localpconfigsnew$pacs-%COMPUTERNAME%-%USERNAME%.xml %APPDATA%RadiantViewerpacs.xml
Den endelige .bat fil ser således ud:
@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
Konklusion
Sådan et «hjemmesløjd» løsning. Vi har allerede prøvet det to gange (i september 2018 og i februar 2019), og indtil videre er alt i orden. Selvfølgelig opdaterer det ikke 100 % af kunderne, men tæt på det tal — de resterende tager vi os af eksternt. Scriptet om .
Kilde: habr.com
