Learn F5 Technologies, Get Answers & Share Community Solutions Join DevCentral

Filter by:
  • Solution
  • Technology
Answers

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.

0
Rate this Question

Answers to this Question

placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

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

0
Comments on this Answer
Comment made 05-May-2015 by David Alfonso 1
Excellent. Would you be able to share the solution with me? It would really help us out.
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

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 namespace

Then, 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
}
0
Comments on this Answer
Comment made 05-May-2015 by David Alfonso 1
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.
0