Forum Discussion
DICOM Echo Monitor
I have been searching for hours for a DICOM Echo iRule or custom monitor with no success. Several other load balancer appliances support DICOM checks but so far not F5. Any advice on how to monitor DICOM server? BTW..TCP and TCP half-open are NOT good for DICOM server. They produce association errors on DICOM/PACS server every 5 seconds which creates unneeded CPU/IO load.
8 Replies
- dubdub
Nimbostratus
Hi David,
I created a .NET web service that wraps an echoscu call to create/verify an assocation between the web server and a DICOM server. The web service takes the node name as a parameter (along with some other ones), and returns a simple "UP"/"DOWN" string. Individual custom HTTP monitors on the F5's point at the web server/port and pass the node name to the web service, then use the Receive string to mark the pool members up or down.
Thanks, Jen
- David_Alfonso_2
Nimbostratus
Excellent. Would you be able to share the solution with me? It would really help us out.
- dubdub_25068
Altostratus
Hi David,
I created a .NET web service that wraps an echoscu call to create/verify an assocation between the web server and a DICOM server. The web service takes the node name as a parameter (along with some other ones), and returns a simple "UP"/"DOWN" string. Individual custom HTTP monitors on the F5's point at the web server/port and pass the node name to the web service, then use the Receive string to mark the pool members up or down.
Thanks, Jen
- David_Alfonso_2
Nimbostratus
Excellent. Would you be able to share the solution with me? It would really help us out.
- dubdub
Nimbostratus
This is the web service code itself, that invokes echoscu. The web server has to be provisioned with the DICOM server so it accepts associations from the web server. Also, the echoscu executable has to be locally available on the web server.
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Web; using System.Web.Services; using System.Diagnostics; using System.IO; using System.Security; using System.Security.Principal; using System.Text; using System.Text.RegularExpressions; namespace MonitorService { [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [System.ComponentModel.ToolboxItem(false)] // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. // [System.Web.Script.Services.ScriptService] public class MonitorService : System.Web.Services.WebService { private bool m_bDebug = false; private string m_szLogFile; public MonitorService() { // Determine if we're in debug mode try { string szValue = System.Configuration.ConfigurationManager.AppSettings["DebugMode"]; if (szValue == "true") { m_bDebug = true; m_szLogFile = System.Configuration.ConfigurationManager.AppSettings["MSLogFile"]; } } catch {} } [WebMethod(Description = "Runs the echoscu command against the given host and port to determine availability.")] public string DicomMonitorAETitle(string szHost, string szPort, string szAEC, bool bAET) { StreamWriter sw = null; Process proc = null; ProcessStartInfo procInfo = new ProcessStartInfo(); string szArguments = ""; string szCommand = ""; string szResult = ""; try { // Default to down szResult = "DOWN"; // Open the log file if needed if (m_bDebug) { sw = new StreamWriter(m_szLogFile, true); } szCommand = Environment.GetEnvironmentVariable("COMSPEC"); if (!bAET) { szArguments = String.Format("/c {0} -v -aec {1} {2} {3}", @"d:\apps\echoscu.exe", szAEC, szHost, szPort); } else { szArguments = String.Format("/c {0} -v -aec {1} -aet {2} {3} {4}", @"d:\apps\echoscu.exe", szAEC, System.Net.Dns.GetHostName(), szHost, szPort); } if (m_bDebug) { sw.WriteLine(String.Format("{0}: DicomMonitor command is [{1}]", System.DateTime.Now, szCommand)); sw.WriteLine(String.Format("{0}: DicomMonitor arguments are [{1}]", System.DateTime.Now, szArguments)); } procInfo.FileName = szCommand; procInfo.Arguments = szArguments; procInfo.UseShellExecute = false; proc = Process.Start(procInfo); proc.WaitForExit(); if (proc.ExitCode != 0) { if (m_bDebug) { sw.WriteLine(String.Format("{0}: DicomMonitor got exit code: {1}", System.DateTime.Now, proc.ExitCode)); } } else { if (m_bDebug) { sw.WriteLine(String.Format("{0}: DicomMonitor echoscu completed successfully", System.DateTime.Now)); } szResult = "UP"; } } catch (Exception e) { if (m_bDebug) { sw.WriteLine(String.Format("{0}: Caught exception: {1}", System.DateTime.Now, e.Message)); } szResult = "DOWN"; } finally { if (sw != null) { sw.Close(); } } return szResult; } // end DicomMonitor } // end class } // end namespaceThen, create a simple web page that consumes the web service:
using System; using System.Collections.Generic; using System.Configuration; using System.Linq; namespace MonitorPage { public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { string szResponse = ""; string szMethod = ""; string szHost = ""; string szPort = ""; string szAEC = ""; string szAET = ""; bool bAET = false; try { // Get the parameters from the URL szMethod = Request.Params["method"]; szHost = Request.Params["host"]; szPort = Request.Params["port"]; szAEC = Request.Params["aec"]; szAET = Request.Params["aet"]; if (szMethod == null || szMethod.Length == 0) { throw new Exception("You must specify a method."); } if (szHost == null || szHost.Length == 0) { throw new Exception("You must specify a host."); } if (szPort == null || szPort.Length == 0) { throw new Exception("You must specify a port."); } if (szAEC == null || szAEC.Length == 0) { throw new Exception("You must specify an AEC value."); } if (szAET != null && szAET.Length > 0 && szAET == "1") { bAET = true; } // Establish the web service object using (myWebServer.MonitorService mService = new myWebServer.MonitorService()) { // Invoke the correct service if (szMethod == "DicomMonitor") { szResponse = mService.DicomMonitorAETitle(szHost, szPort, szAEC, bAET); } } // Return the response Label1.Text = szResponse; } catch (Exception e1) { Label1.Text = e1.Message; } } } }Then create a monitor that calls the web page on the web server (1.1.1.1 in this example, which hosts both the web service and the web page itself) for each DICOM server in your pool, and associate the monitors at the pool member level (not the pool itself):
ltm monitor http Dicom_server1 { defaults-from http destination 1.1.1.1:http interval 30 recv UP send "GET http://myWebServer.domain.com/MonitorPage/Default.aspx\?method=DicomMonitor&host=server1&port=105&aec=SERVER1_AE HTTP/1.1\\r\\nHOST: myWebServer\\r\\nConnection: Close\\r\\n\\r\\n" time-until-up 0 timeout 91 }- David_Alfonso_2
Nimbostratus
Thank you very much. I have obtained a windows binary of echoscu and will work with our team to see if we can implement this improvement.
- dubdub_25068
Altostratus
This is the web service code itself, that invokes echoscu. The web server has to be provisioned with the DICOM server so it accepts associations from the web server. Also, the echoscu executable has to be locally available on the web server.
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Web; using System.Web.Services; using System.Diagnostics; using System.IO; using System.Security; using System.Security.Principal; using System.Text; using System.Text.RegularExpressions; namespace MonitorService { [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [System.ComponentModel.ToolboxItem(false)] // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. // [System.Web.Script.Services.ScriptService] public class MonitorService : System.Web.Services.WebService { private bool m_bDebug = false; private string m_szLogFile; public MonitorService() { // Determine if we're in debug mode try { string szValue = System.Configuration.ConfigurationManager.AppSettings["DebugMode"]; if (szValue == "true") { m_bDebug = true; m_szLogFile = System.Configuration.ConfigurationManager.AppSettings["MSLogFile"]; } } catch {} } [WebMethod(Description = "Runs the echoscu command against the given host and port to determine availability.")] public string DicomMonitorAETitle(string szHost, string szPort, string szAEC, bool bAET) { StreamWriter sw = null; Process proc = null; ProcessStartInfo procInfo = new ProcessStartInfo(); string szArguments = ""; string szCommand = ""; string szResult = ""; try { // Default to down szResult = "DOWN"; // Open the log file if needed if (m_bDebug) { sw = new StreamWriter(m_szLogFile, true); } szCommand = Environment.GetEnvironmentVariable("COMSPEC"); if (!bAET) { szArguments = String.Format("/c {0} -v -aec {1} {2} {3}", @"d:\apps\echoscu.exe", szAEC, szHost, szPort); } else { szArguments = String.Format("/c {0} -v -aec {1} -aet {2} {3} {4}", @"d:\apps\echoscu.exe", szAEC, System.Net.Dns.GetHostName(), szHost, szPort); } if (m_bDebug) { sw.WriteLine(String.Format("{0}: DicomMonitor command is [{1}]", System.DateTime.Now, szCommand)); sw.WriteLine(String.Format("{0}: DicomMonitor arguments are [{1}]", System.DateTime.Now, szArguments)); } procInfo.FileName = szCommand; procInfo.Arguments = szArguments; procInfo.UseShellExecute = false; proc = Process.Start(procInfo); proc.WaitForExit(); if (proc.ExitCode != 0) { if (m_bDebug) { sw.WriteLine(String.Format("{0}: DicomMonitor got exit code: {1}", System.DateTime.Now, proc.ExitCode)); } } else { if (m_bDebug) { sw.WriteLine(String.Format("{0}: DicomMonitor echoscu completed successfully", System.DateTime.Now)); } szResult = "UP"; } } catch (Exception e) { if (m_bDebug) { sw.WriteLine(String.Format("{0}: Caught exception: {1}", System.DateTime.Now, e.Message)); } szResult = "DOWN"; } finally { if (sw != null) { sw.Close(); } } return szResult; } // end DicomMonitor } // end class } // end namespaceThen, create a simple web page that consumes the web service:
using System; using System.Collections.Generic; using System.Configuration; using System.Linq; namespace MonitorPage { public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { string szResponse = ""; string szMethod = ""; string szHost = ""; string szPort = ""; string szAEC = ""; string szAET = ""; bool bAET = false; try { // Get the parameters from the URL szMethod = Request.Params["method"]; szHost = Request.Params["host"]; szPort = Request.Params["port"]; szAEC = Request.Params["aec"]; szAET = Request.Params["aet"]; if (szMethod == null || szMethod.Length == 0) { throw new Exception("You must specify a method."); } if (szHost == null || szHost.Length == 0) { throw new Exception("You must specify a host."); } if (szPort == null || szPort.Length == 0) { throw new Exception("You must specify a port."); } if (szAEC == null || szAEC.Length == 0) { throw new Exception("You must specify an AEC value."); } if (szAET != null && szAET.Length > 0 && szAET == "1") { bAET = true; } // Establish the web service object using (myWebServer.MonitorService mService = new myWebServer.MonitorService()) { // Invoke the correct service if (szMethod == "DicomMonitor") { szResponse = mService.DicomMonitorAETitle(szHost, szPort, szAEC, bAET); } } // Return the response Label1.Text = szResponse; } catch (Exception e1) { Label1.Text = e1.Message; } } } }Then create a monitor that calls the web page on the web server (1.1.1.1 in this example, which hosts both the web service and the web page itself) for each DICOM server in your pool, and associate the monitors at the pool member level (not the pool itself):
ltm monitor http Dicom_server1 { defaults-from http destination 1.1.1.1:http interval 30 recv UP send "GET http://myWebServer.domain.com/MonitorPage/Default.aspx\?method=DicomMonitor&host=server1&port=105&aec=SERVER1_AE HTTP/1.1\\r\\nHOST: myWebServer\\r\\nConnection: Close\\r\\n\\r\\n" time-until-up 0 timeout 91 }- David_Alfonso_2
Nimbostratus
Thank you very much. I have obtained a windows binary of echoscu and will work with our team to see if we can implement this improvement.
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)Recent Discussions
Related Content
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com