46.2. Manager REST client API.

While the APIs described in the previous section are required to to define the configuration of an experiment; software that interacts with the running program manager will do so via one or more of the REST interfaces and APIs provided for them.

REST, or REpresentational State Transfer interfaces are a mechanism to use normal web (http and https) protocols to map URLs and query/form data to operations in a server. The NSCLDAQ manager program provides several URL families (or domains) and we also provide Tcl packages to allow your applications to interact with those domains.

When the manager starts up, it uses the NSCLDAQ port manager to advertise its REST service port. By default this port is given the service name DAQManager. REST interfaces, in general, do not make use of persistent connections. In order to be robust with respect to manager restarts, the rest client code looks up the service port for each request.

In the remainder of this section we will:

46.2.1. REST Client for State Transitions

This client package, stateclient provides a REST client to the State domain of the DAQ manager. In order to use it, you must know the host in which the DAQ manager is running and the user that ran the manager (the NSCLDAQ port manager advertises services as servicename-username pairs).

The REST client is exported in an object oriented manner. Applications create an inteface object and then invoke its methods to perform various actions. Reference material is available: stateclient

The sample application below gets the current state of the system, produces a list of the valid next states and then attempts a transition into the first of the valid next states. Please don't try this yourself, in general the state transition we're going to trigger makes little to no sense.

The application accepts the host and username as command parameters.

Example 46-17. Sample State Transition REST Client


if {[array names env DAQTCLLIBS] ne ""} {
    lappend auto_path $env(DAQTCLLIBS)
}
package require stateclient     (1)

proc usage {msg} {              (2)
    puts stderr "Usage: "
    puts stderr "   $::argv0 host user"
    puts stderr "Where:"
    puts stderr "   host is the host in which the manager is running and"
    puts stderr "   user is the user that started the manager."
    exit -1
}


if {[llength $argv] != 2} {
   usage
}

set host [lindex $argv 0]     (3)
set user [lindex $argv 1]

StateClient client -host $host -user $user  (4)
puts "Current state: [client currentState"]  (5)

set nextStates [client nextStates]          (6)
puts "Allowed next states are [join $nextStates {, }]"
client transition [lindex $nextStates 0]    (7)

client destroy                              (8)
exit 0


            
(1)
In order to use the REST state transition client, it is necessary to pull the stateclient package into your script.
(2)
This proc outputs the program usage. It'll be called if the user does not provide the correct command parameters.
(3)
These two lines of code extract the host and the username from the command line parameters.
(4)
Constructs the client object. The typical form of object construction in Tcl object systems is classname objectname ?options...?. Where classname is the name of the class whose instance we're constructing. objectname is the name to give to the object. In Tcl objects are represented as command ensembles with the object name as the base command name.

Options can also be provided to construction and these, in this case, provide the host and username. The result of this construction is a command ensemble named client whose subcommands are object method invocations. Note that, as with Tk object construction, construction also returns the name of the object. In some object systems like e.g. snit, the special object name %AUTO% makes the object system assign a unique object name to the constructed object.

(5)
The currentState method of a StateClient object returns the name of the current state in which the state machine is now in.
(6)
The nextStates method of StateClient objects returns a list of valid next state names. That is a list of valid transitions out of the current state. Note that the code that follows assumes that the state we are in is not terminal, that is there is at east one valid next state.
(7)
Requests the manager to make a state transition to the first of the legal next states (we're assuming there is at least one legal next state). The REST request completes only after the state transition has completed.
(8)
The StateClient object has a pre-defined method destroy which destroys the object. We call this before exiting the program.

46.2.2. REST Client for Program Status

The programstatusclient package provides an object oriented interface to the REST server domain that exports information about container and program status. It exports a single class: ProgramClient. Instances of that object support the status method in addition to the pre-defined destroy, configure and cget methods

Reference information is available: programstatusclient.

The example below creates a client, requests the status and displays a list of which containers are activated and in which systems they have been activated.

Example 46-18. Using The programstatusclient Package


if {[array names env DAQTCLLIBS] ne ""} {
    lappend auto_path $env(DAQTCLLIBS)
}

package require programstatusclient    (1)

proc usage {} {
    puts stderr "Usage:"
    puts stderr "  $::argv0  host user"
    puts stderr "Where:"
    puts stderr "   host is the host on which the manager is running and"
    puts stderr "   user is the name of the user running the manager"
    exit -1
}

if {[llength $argv] != 2} {
   usage
}

set host [lindex $argv 0]
set user [lindex $argv 1]
ProgramClient client -host $host -user $user  (2)

set info [client status]                     (3)
set containers [dict get $info containers]
puts "Active Containers:"
foreach container $containers {
    set name [dict get $container name]
    set image [dict get $container image]
    set activations [dict get $container activations]
    if {[llength $activations] > 0} {
      puts "$name ($image) is active in [join $activations {, }]"
    }
}

client destroy                              (4)
exit 0
            
(1)
To use the package it must be pulled into the script via the package require command shown.
(2)
This constructs a ProgramClient object that will be used to communicate with the REST server. The -host and -user options describe how to perform service discovery.

The user and host can be provided at construction time as shown here or any time prior to the first REST request using the configure method.

The object name will be client. This will be a new base command for a command ensemble who's members are the methods supported by the object.

(3)
The status method/subcommand provides the status of all containers and programs. The return value is a dict with two keys: containers that provides information about container activations and programs which provides information about the programs that have been defined and their status.

In this sample, we just output information about the containers. The value of the containers key is a list of dicts. Each of the dicts describes a container. For this application we only need to know that name is the container name, image is the path to the container image file in the host filesystem and activations is a list of the hosts on which the container is activated (this will be an empty list if the container is not active).

Subsequent code iterates over the containers outputting, for each container with at least one activation, information about the container and where it's active.

(4)
This line destroys the client object.

46.2.3. REST Client for Key Value Store

The kvclient package provides an object oriented API to the key value store. Using this package, you can set and get values of keys as well as list keys and dump the complete contents of the store.

Full documentation on this package is available at kvclient. In the example below we set the title key and dump the entire KV store. The title key is used by the Readout support software to set the run titles in the various Readouts used by the experiment.

Example 46-19. Using the kvclient Package.


if {[array names env DAQTCLLIBS] ne ""} {
   lappend auto_path $env(DAQTCLLIBS)
}
package require kvclient     (1)

proc usage {} {
   puts stderr "Usage"
   puts stderr "   $::argv0 host user new title words"
   puts stderr "Where:"
   puts stderr "   host and user specify the host running the manager and
   puts stderr "   user that started it.  The remaining parameters are
   puts stderr "   the new title to set.  They will be combined separated by spaces"
   exit -1
}

if {[llength $argv] < 3} {
    usage
}

set host [lindex $argv  0]
set user [lindex $argv 1]
set title [lrange $argv 2 end]           (2)

KvClient client -host $host -user $user   (3)
client setValue title $title              (4)

puts "Dump of kv store:"

dict for {name value} [client list] {               (5)
   
   puts "$name :     $value"
}
client destroy                          (6)

            
(1)
In order to make calls to the Key Value REST client API, the kvclient package must be pulled into the program.
(2)
This little bit of Tcl makes a variable named title from the words on the command line that follow the host and user (words 2 through the end).
(3)
Constructs a Key Value store REST client object specifying the -host and -user options from the values on the command line. Note that constructing the object does not network operations. Network operations, like service discovery and connecting to the server are only done when a REST request is made.
(4)
The setValue method accepts two parameters, the name of an existing key value store key and the new value to give to it. This sets the key title to the title words the user passed in on the command line.
(5)
The list method dumps the entire key value store, returning it as a dict whos keys are key value store keys and whose values are the values of the corresponding key value store key.
(6)
The destroy method destroys the client when we are done using it. Note that given the nature of interactions with REST servers, KvClient instance objects are quite light weight.

46.2.4. REST Clients for Event Log Management

The loggerrestclient package provides an object oriented interface to the REST domain (/Loggers) in the manager server that manages event loggers. Reference material for this package is available loggerrestclient

The following example program enables all loggers, sets the recording state on and starts the loggers.

Example 46-20. Using the loggerrestclient Package


if {[array  names env DAQTCLLIBS] ne ""} {
   lappend auto_path $env(DAQTCLLIBS)
}
package require loggerrestclient      (1)

proc usage {} {
   puts stderr "Usage:"
   puts stderr "  $::argv0 host user"
   puts stderr "Where:"
   puts stderr "   host is the host on which the manager server is running."
   puts stderr "   user is the user who started the server.
   exit -1
}

if {[length $argv] != 2} {
   usage
}

set host [lindex $argv 0]
set user [lindex $argv 1]


LoggerRestClient client -host $host  -user $user  (2)

foreach logger [client listLoggers] {             (3)
    client enableLogger [dict get $logger destination]  (4)
}
client record 1                         (5)
client start                            (6)

client destroy                          (7)



            
(1)
Using the logger rest client API means applications must package require loggerrestclient as this package contains the implementation of that package.
(2)
Constructs an instance of a client to a manager server that will interact with the logger REST server domain.k
(3)
The listLoggers method of a logger REST client instance returns a list of dicts. Each dict includes, among other keys, a destination key which contains the logger destination. The logger destination is required, by the API to be unique and is used in the REST API, rather than the invisible id, to identify loggers.
(4)
The enableLogger method enables the logger designated by its destination. If that logger is already enabled this call silently has no effect.
(5)
The record method sets the state of the global recording flag.
(6)
Starts all loggers that should start. Since we've previously enabled all loggers and ensured the global recording flag is true, this will start all defined loggers.
(7)
Destroys the logger REST API Object