Skip to content

Websocket Access

A web socket is provided to retrieve a stream of events. This can be accessed by hitting a URL in the form of:

https://<IP>:<API_PORT>/api/v3/ws?Token=<AUTH_TOKEN>

The URL will require authentication, but once authorized, the resulting web socket will receive events.

Events can be filtered by submitting register filters to the websocket listener.

Register for Events

The events desired must be registered for. This is done by sending a register request to the server. By sending, register *.*.*, this will cause all events that the authorized user can see to be delivered to the websocket receiver.

Multiple registers (and the corresponding deregister) are allowed.

The general form is:

register type.action.key or register type.action.key.filter

The fields are:

  • type - the type of object (e.g. profiles, machines, ...)
  • action - the action of the object (e.g. create, save, update, destroy, ...)
  • key - the specific key of the object (e.g. machine uuid, profile name, ...)
  • filter - A filter that can be used for more specific matching of events beyond the type.action.key matches.

Some simple example are provided in the DRP source tree:

Event specifiers

The type, action, and key fields in an event specifier can have the following values:

  • * to indicate all possible values of that field count towards a match.
  • A comma-separated list of values appropriate to the field with no intervening spaces -- object types for the type field, action names for the action field, and key values for the key field.

There are a couple of special cases to enable efficient handling of certain job-related events:

  • If the type is machine_jobs, then a job event whose Machine field matches the key of the event specifier will match the event assuming the other fields also match.
  • If the type is work_order_jobs, then a job event whose WorkOrder field matches the key of the event specifier will match the event assuming the other fields match.

The filter field in the event specifier is optional. If it is present, it should contain a filter defined by the client-side compatible filter language.

Client compatible filter language

This language is designed to be easily implementable in client API libraries and operate identically on the native Go objects and their JSON serialization. It is available on the server side if the server advertises the websocket-changed-filter feature flag, otherwise it can also run on the client side as an event post-processor.

  • value is the JSON representation of the value you want to filter on.
  • fields is either a dot-separated string or an RFC6901 compliant JSON pointer specifying the field in a potentially nested struct or array to look up.
  • term is any syntactically correct filter expression.
  • terms is a comma separated list of syntactically correct filter expressions.
  • And(terms) will match of all of the terms match. Terms are tested from left to right, and the first one that does not match stops testing.
  • Or(terms) will match if any of the terms match. Terms are tested from left to right, and the first one that matches stops testing.
  • Not(term) returns the opposite of the term.
  • fields=Exists() checks to see if there is a value at fields at all, no matter what the value may be.
  • fields=Eq(value) checks to see if the value at fields is equal to the passed in value.
  • fields=Ne(value) checks to see if the value at fields is not equal to the passed in value.
  • fields=Re(value) checks to see if the value at fields matches the passed-in regular expression.
  • fields=In(value,value...) checks to see if the value at fields matches any of the passed-in values. It is equivalent to Or(fields=Eq(value1),fields=Eq(value2),...).
  • fields=Nin(value,value...) checks to see if the value at fields does not match any of the passed-in values. It is equivalent to Not(Or(fields=Eq(value1),fields=Eq(value2),...)).
  • fields=Changed(from,to) behaves specially if it is matching against either a models.Event or an api.RecievedEvent. from and to must both be valid JSON values, the same as value.
  • If the event being tested has non-nil Object and Original fields, Changed will return false if fields is not present in both objects or if it is present and identical in both objects.
  • If from is specified and the value at fields in Original is not Eq to it, Changed will return false.
  • If to is specified and the value at fields in Object is not Eq to it, Changed will return false.
  • Otherwise, Changed will return true. If Changed is testing anything besides a models.Event or an api.RecievedEvent, it returns true if to is not specified or Eq(to) returns true.

Deregister Events

If you no longer wish to receive specific events you have registered for, you may use the deregister command. The command syntax is exactly like the register command.

The general form is:

deregister type.action.key or deregister type.action.key.filter

The deregister message must correspond to a previous register message.

Websocket Tools

Most modern languages provide websocket libraries that you can use to create listeners in a given language. Some examples include (this is not an exhaustive list):

There are several extensions/add-ons for web browsers that will allow you to do basic testing of websocket listening. Here at RackN, we have used the following with some success:

There is a simple sample Python script available in the Digital Rebar Provision repo for reference, see the Websocket Integrations: page for further details.

Monitoring Connections

Digital Rebar has an API endpoint for listing active websocket and REST Connections under GET /api/v3/connections. This list of connections contains information such as create time, principal, address, and if the connection is a websocket.

Connections for specific machines can be accessed via GET /api/v3/machines/:uuid/connections. Clusters and Resource brokers have the similarly named API endpoints.

New connections and disconnections can be monitored by the connections.create.<principal> event. This is useful as individual runner connections can be monitored with connections.create.runner:<uuid>

A combination of the machine connections API endpoint and connection events can be used to monitor a relative "online" state of a machine's runner, a user's portal session, or the connectivity of a plugin.

Note

While connection events come in with Principal for the event key, connections are unique by RemoteAddr. This is because Principal, while not unique, is more useful. RemoteAddr is used as the key for GET /api/v3/connections/:RemoteAddr

Example Information

Here is a simple walk through of basic testing on how to use websockets with Digital Rebar. Please note this is fairly basic, but it should get you started on how to interact with and use websockets. This example was tested, using the " Simple Websocket Client" in both Chrome and Firefox that is listed above.

We assume you have the DRP endpoint installed on your localhost in these examples. You can adjust the IP address/hostname to point to a remote DRP Endpoint, just ensure you have access to Port 8092 (by default, or the API port you specify if you changed the default).

URL: wss://127.0.0.1:8092/api/v3/ws?token=rocketskates:r0cketsk8ts

Note that the token information is a set of credentials with permissions to view events. This example uses the default username/password pair. You may also create and specify access Tokens for the websocket client to use.

In the Request input box, enter your register filter you'd like to receive events for.

Request: register profiles.*.*

This example will only output websocket events related to Parameters. Now create and delete a few test parameters

# now create a `bar` param on the `global` profile
drpcli profiles set global param bar to blatz

# now remove the param from the `global` profile
drpcli profiles remove global param bar

...and you should see events like:

{"Time":"2017-12-21T23:26:43.412554192Z","Type":"profiles","Action":"save","Key":"global","Object":{"Validated":true,"Available":true,"Errors":[],"ReadOnly":false,"Meta":{"color":"blue","icon":"world","title":"Digital Rebar Provision"},"Name":"global","Description":"Global profile attached automatically to all machines.","Params":{"bar":"blatz","change-stage/map":{"centos-8-install":"packet-ssh-keys:Success","discover":"packet-discover:Success","packet-discover":"centos-8-install:Reboot","packet-ssh-keys":"complete-nowait:Success"},"kernel-console":"console=ttyS1,115200"}}}
{"Time":"2017-12-21T23:27:15.218761478Z","Type":"profiles","Action":"save","Key":"global","Object":{"Validated":true,"Available":true,"Errors":[],"ReadOnly":false,"Meta":{"color":"blue","icon":"world","title":"Digital Rebar Provision"},"Name":"global","Description":"Global profile attached automatically to all machines.","Params":{"change-stage/map":{"centos-8-install":"packet-ssh-keys:Success","discover":"packet-discover:Success","packet-discover":"centos-8-install:Reboot","packet-ssh-keys":"complete-nowait:Success"},"kernel-console":"console=ttyS1,115200"}}}