infoServ IOC information server (NSCL/FRIB)

Release 1.1.0.1
by John Priller
April 9, 2015

Contents


Introduction

Why?

A question often heard from EPICS newcomers is "how can I tell what PVs are on an IOC?"

There's no simple answer. Nothing built into EPICS Base (at least not in version 3) will give a remote client that information. Many EPICS facilities develop their own methods for keeping track of what PV names exist in their systems, using everything from spreadsheets and complex databases that can list what SHOULD be on any given IOC, to simply having IOC startup scripts dump the output of a 'dbl' command to a file and using a cron script to do processing on these files later.

What PVs are on an IOC can be an important thing to know. Developers of control screens want to know what PVs exist for the systems they're working with, EPICS support staff need to know what PVs to include when configuring EPICS channel archiving. In my support work I found myself needing to know this sort of thing all the time.

I also found that I wanted know more than just the PV names. I wanted to use "info" fields to flag PVs for save/restore or for archiving, and for that I needed to be able to determine remotely what these fields were. I wanted to have access to the actual database files the IOCs were using so I could check whether the PVs used in record link fields actually existed, and for that I'd have to identify all the aliases that PV names might have. To parse database and substitution files I often needed to know what the values of environment variables were.

The obvious occurred to me: the IOC task has access to all this information. So why not write an EPICS IOC support module that allows external clients to access this information via a method convenient for scripting languages like Python, for example HTTP URLs and JSON encoding to make it easier for the poor script designer (me) to pull out the various bits desired?

That's what infoServ does. In addition to a PV list with alias and info-fields data it will also return the contents of files from the IOC application's directory, the values currently assigned to environment variables, and provide some (admittedly rather basic) information about the IOC like how long it's been up and what version of EPICS it's running. It also allows other support modules to register their own URL-handlers to provide any information they want to make available.

... and maybe Why Not

The problem with a service that delivers IOC information, of course, is that it allows people to get at information that you might not want them to have. The contents of a file in the IOC's directory might contain proprietary code or other information, or maybe even contain passwords. There could be intellectual property considerations with source files or stored data. Those sorts of things need to be considered when deploying this service.

With that out of the way, let's proceed...


Requirements

The infoServ module has no special requirements and uses no external support modules. It should work equally well in any EPICS build environment with a c++ compiler. It has been testing on 32-bit and 64-bit Linux with EPICS R3.14.12.2, Sun/Solaris 5.8 with EPICS R3.14.9, and VxWorks 5.4 with EPICS 3.14.6.

Sites can create their own additions to the infoServ service via an URL-handling API it provides (see API for adding URLs). Requirements for those would of course depend on what these additions need.


What the data looks like

For a demonstration of what an IOC's infoServ data looks like in a web browser, click here.


Usage

Adding the infoServ support module to an IOC application

  1. Obtain the latest infoServ gzipped tarball (see the download section for the link) and unpack it in your IOC's support modules directory.

  2. Edit the infoServ/configure/RELEASE file to set the EPICS_BASE environment variable to what your IOC is using.

  3. Compile the infoServ module:

    (cd to infoServ top directory)
    make
  4. Add a line for infoServ to your IOC's $(TOP)/configure/RELEASE file, pointing to where infoServ is at in your support modules directory tree. For example:

    INFOSERV = $(SUPPORT)/infoServ
  5. Add lines to your IOC application's src/Makefile to include the infoServ.dbd file and library in the build. For example:

    $(PROD_IOC)_DBD += infoServ.dbd
    PROD_LIBS += infoServ

    If you want to include the demonstration infoServ add-in testAddIn, then add this line also:

    $(PROD_IOC)_DBD += testAddIn.dbd
  6. Add line(s) to your IOC's startup script for starting the infoServ service and (optionally) setting the port number the service should use. These lines can occur before or after iocInit() is called, it doesn't matter. Changing the port number while infoServ is running is allowed also.

    infoServSetParam("Port",7729)
    infoServStart()

    If multiple IOCs are running on the same IP address then each one running infoServ needs to have a unique port number assigned. The default port number if none is specified is 7729.

  7. Recompile your IOC to build infoServ into it:

    (cd to IOC's top directory)
    make clean
    make
  8. Restart your IOC. Then point a web browser at the name/IP-address of the IOC and the infoServ port number used (the default is 7729). For example:

    http://testioc.where.i.am:7729

    You should see the infoServ home page with a link to "help".

Built-in informational URLs

For a demonstration of what the data these URLs return looks like, see the What the data looks like section.

/help? Help page, essentially what you're seeing here...
/info? (JSON data) server information
/pvs?[fields=FIELD[,FIELD2...]] (JSON data) get list of records on IOC, and optionally field values
/env?VARNAME[,VARNAME2...] (JSON data) get values of IOC environment variables
/file?FILENAME (TEXT) get contents of a given file
absolute directory paths ONLY
MUST be subdir of $(TOP) or allowed by IOC call to infoServAllowFilePath()
/fileexists?FILENAME (JSON) whether the given file exists, same limitations as /file?
/filepaths? (JSON data) get list of allowed file paths for /file? and /fileexists?
/startup? (JSON data) get IOC startup script info

IOC shell commands

A number of IOC shell commands are provided to configure module parameters and help diagnose problems, these are detailed below.

infoServStart()

Starts the infoServ service on the IOC. The service can stopped at any time with infoServStop().

infoServStop()

Stops the infoServ service on the IOC. The service can be restarted at any time with infoServStart().

infoServSetParam(parameter,value)

Sets a given module parameter, identified by a text string, to the given integer value. Invoking this function without any arguments displays the current values of all configurable parameters.

Unless specifically noted in their description, parameters can be changed at any time.

The following parameters are provided:

Parameter Default Description
DebugLevel 0 Debugging level. The higher the level the more debug messages will be printed.
Port 7729

The port number infoServ should listen for connections on.

Every IOC running on the same host/IP needs to have a unique port number assigned to it.

MaxClients 10

The maximum number of simultaneous client connections to allow.

SelectTimeoutSec 0

This (along with the SelectTimeoutUSec parameter) sets the timeout infoServ uses in its socket select() call. This is a fiddly bit that probably never needs to be touched, but is exposed in case anyone wants to do any tests with it.

SelectTimeoutUSec 100000

(see SelectTimeoutSec, this is the microseconds portion)

ClientLingerSec 5

How long client socket connections "linger" after all requested data has been sent to them (the SO_LINGER sockets option). This may need to be increased for very slow clients or very busy networks.

ClientTimeoutSec 10

How long clients have to complete sending their request after they initially connect before the connection is considered timed-out and infoServ drops the connection. This may need to be increased for very slow clients or very busy networks.

ThreadRecycleSec 30

A separate handling thread is created for each client connection. Rather than disposing of these immediately after a client disconnects, these are kept for ThreadRecycleSec seconds so if another client connects in that time it can be assigned to the currently-unused thread.


infoServAllowFilePath(directory_path)

To prevent clients from getting at Very Important Files on IOCs (for example /etc/passwd ?) all requests to the /file? and /fileexists? URLs must be absolute path names (no ./ or ../ allowed) and are restricted to files within a set of allowed directory names.

The IOC's $(TOP) directory is always allowed by default. Any additional directories desired can be added to the list using this command.

The /filepaths? URL will return a JSON-encoded list of the allowed directories.

infoServReport

Displays a short summary of the infoServ service's status. It looks something like this:

infoServ 1.0.0.2
server state : started
up seconds   : 10383
client stats:
  current client count  : 0
  highest client count  : 1
  created client count  : 3
  recycled client count : 4
  deleted client count  : 3
      

API for adding URLs

This topic is a little too involved to cover in much detail. There is a demo add-in for infoServ called testAddIn if you want to see what a complete example with source code looks like (testAddIn.cpp in the infoServ src directory). To try that out:

While testAddIn is running its two supported URLs (/bob? and /tim?) will appear in the infoServ /help? content and a line for it will appear in the /info? URL's "urlhandlers" section. If it's stopped these will no longer appear.

To create an add-in from scratch the bullet-points below should be enough to get started, feel free to email me (see the Support section) if there's anything you'd like to do but aren't certain how.

NOTE: User-registered URL handlers will be called in reverse-order of when they registered. This allows for user URLs to override the behavior of built-in URLs if desired.


Issues/Problems

This section provides a collection of issues discovered in using the infoServ service, with suggested work-arounds when available.

Relative path used for IOC startup

One of the many things I want to do with infoServ is get the IOC's startup script file, so I can parse it for what databases and substitution files it loads and then parse them as well. The built-in /startup? and /file? URLs are included with that in mind.

But there's a problem. The infoServ service can't easily tell what the startup script file name is or what directory it was launched from. On VxWorks it's easy, there's systems calls that will tell you. But on a Soft IOC you have to hope the user, the automatic boot-script, or whatever launched the IOC application used absolute paths in the command. For example you want to see something like:

/home/epics/R3.14.12.2/apps/testDev/iocBoot/iocFrib/st.cmd

not:

./st.cmd

The solution of course is to make sure IOC's are always started with an absolute path in the command.


Download

The most recent version of the infoServ support module can be downloaded from the NSCL/FRIB Control Software Group's website at:
https://groups.nscl.msu.edu/controls/


Support

For questions, comments, suggestions for improvement or for anything else related to this module, please feel free to contact John Priller at:
priller@frib.msu.edu


(END)