Предистория
В една медицинска организация внедриха решения на база PACS-сървъри Orthanc и DICOM-клиент Radiant. По време на настройката установихме, че всеки DICOM-клиент трябва да бъде описан в PACS-сървърите по следния начин:
- Име на клиента
- AE-име (трябва да бъде уникално)
- TCP-порт, който автоматично се отваря от страната на клиента и приема DICOM-изследвания от PACS-сървъра (т.е. сървърът както дава на клиента – иницира връзката първи)
- IP адрес
След настройката на Radiant клиентите получиха следната информация за размисъл – при всеки клиент настройката на софтуера с посочените по-горе параметри водеше до запълване на файла pacs.xml, който се намираше в профила на потребителя (пътят: %APPDATA%RadiantViewerpacs.xml). При това конфигурацията на един клиент се отличаваше от друга минимум с два параметъра (AE-името при всички е различно, а портът е предимно един и същ, освен при терминалните клиенти, работещи на един и същи сървър – там портовете също трябваше да бъдат задавани различно).
Пример на файла pacs.xml по :
Приблизително половин година всичко беше добре, системата заработи... и тук до нас достигнаха „подводни камъни»:
- Трябва да въведем в експлоатация няколко нови PACS-сървъра, които да заменят старите (където свършваше мястото на дисковете). PACS сървърите са във виртуални машини, но не става въпрос за това;
- Трябва по някакъв начин централизирано да променим уникалните конфигурации (с два отличаващи се параметъра) на 200 машини (броят им редовно нарастваше);
- Като се имат предвид темповете на растеж на обемите на изследванията, решението трябва да бъде не еднократен, а тиражируем и редовен (например, 1 път на 3-5 месеца).
Решението е по-долу.
Избор на инструменти за решаване на задачата
В началото имаше опити да се намери някакво решение, което на страната на клиента променяше файла pacs.xml и внасяше в него промени в списъка на PACS-сървърите, без да докосва настройките на AE-името и TCP-порта. Windows клиентите по онова време бяха на база както Windows XP, така и Windows 7 – затова имаше опити да се напише нещо на база VBScript. Но, за съжаление, не успях да се справя с такава задача, поради напълно отсъстващ опит в писането на нещо сложно и комплексно на този език. Опитите да намеря и пренапиша също не увенчаха с успех (тук трябва да се отбележи, че в главата ми вече имаше друг план, така че не се занимавах с VBScript повече от 3-4 часа).
В крайна сметка се спрях на следното решение:
- Съберете всички файлове pacs.xml на едно място на някой сървър в мрежов ресурс с групови политики;
- Променете файловете накуп (опит с решаване на подобни задачи вече имаме – с помощта на Perl);
- Също така, с помощта на групови политики, актуализирайте настройките на клиентите.
Събиране на файлове с помощта на групова политика
Най-простата част е, когато клиентът влезе в своя профил, той с правата си изпълнява определен .bat файл, в който е написано:
echo off
If exist %APPDATA%RadiantViewerpacs.xml copy %APPDATA%RadiantViewerpacs.xml srv.test.localpconfigs$pacs-%COMPUTERNAME%-%USERNAME%.xml
По този начин на сървъра в скрит ресурс ще се натрупват файлове pacs.xml, чиито имена ще съдържат информация от кой компютър и от кой потребител е копиран този конфиг.
Най-трудното беше да изчакаме, докато всички потребители приложат тази политика.
Промяна на конфигурации с помощта на Perl скрипт
Нужно е под Windows от компанията ActiveState, както и модулът XML::Writer, който може да се инсталира с командата ppm install XML-Writer.
Самият скрипт се оказа доста прост:
use XML::Writer;
# Отварям папката с отчетите, обработваме списъка (премахваме излишното):
$report_dir = "C:Perl64WORKPACS-xml3";
opendir(DIR, "$report_dir") or die "Не мога да отворя папката с отчетите!";
@report_files = readdir DIR;
shift (@report_files); # премахваме точката от елементите на масива (.)
shift (@report_files); # премахваме две точки от елементите на масива (..)
# print "@report_files";
closedir(DIR);
# Започваме да обработваме файловете - един по един. Нужно е да считаме параметър AET и номер на порта в променливите.
foreach $analiz_file (@report_files)
{
$full_path_to_file="C:Perl64WORKPACS-xml3".$analiz_file;
open (INFO, $full_path_to_file);
while ($line = )
{
# Променливите $aet и $port съдържат уникални данни за всеки XML файл:
my ($other1, $aet, $other2, $port, $other3) = split /"\/, $line, 5;
# Ако се срещне редът listener - достигнали сме нужния ред и можем да формируем нов XML:
if ($other1 =~ 'listener')
{
# Формируем нов XML с нужните полета и данни:
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');
# Слагаме готовия XML в променлива:
my $xml = $writer->end();
# Подготвяме файла за презапис:
$rewritexml = $full_path_to_file;
# Презаписваме XML файлове с новите данни:
open (NEWXML, "> $rewritexml");
print NEWXML $xml;
close (NEWXML);
}
}
}
Принцип на работа:
- Отварям каталога, в който сме събрали конфигурации pacs.xml от клиентите и слагаме списъка с файлове в масив от скалари (@report_files);
- В цикъл обработваме по един файл и четем го ред по ред;
- С помощта на split разделяме всяка строка на 5 части, използвайки кавичките като разделител;
- Намираме строката с думата listener и слагаме в две променливи уникални за всеки файл данни (AE-име на клиента и номер на TCP порта);
- След това просто формираме нов XML файл, вписваме в него уникалните параметри и след това добавяме нужното количество PACS сървъри с техните параметри – т.е. то, заради което всичко това беше започнато)
- Презаписваме новия XML файл върху стария.
Нужно е да се отбележи, че всъщност аз използвам този скрипт не напълно автоматично – по същество копирам събираните конфигурации в отделен каталог и след това пускам скрипта, променяйки ги всички наведнъж. Следва селективна проверка – и конфигурациите могат да се разпределят обратно по машините.
Разпространение на променените pacs.xml файлове по клиентите
Най-простото, което ми дойде на ум – да внеса промени в вече работещ .bat файл, който събира конфигурации от клиентите и да добавя ред:
If exist %APPDATA%RadiantViewerpacs.xml copy /Y srv.test.localpconfigsnew$pacs-%COMPUTERNAME%-%USERNAME%.xml %APPDATA%RadiantViewerpacs.xml
Итоговият .bat файл изглежда така:
@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
Заключение
Такова е «наколеночно» решение. Опробвахме го вече два пъти (в септември 2018 и през февруари 2019), летенето е нормално. Разбира се, не обновява 100% от клиентите, но близо до това значение — останалите дооправяме дистанционно. Скриптът по .
Източник: habr.com
