Remote Session Configuration#

Configuring a remote session relies a great deal on the resources and requirements of a specific site. Ansys Dynamic Reporting provides some core functionality that simplifies the delivery of VNC-based rendering solutions to end-users. These features include:

  • An integrated VNC client run in a web-browser. This allows for a true zero-footprint install solution that only relies on Ansys Dynamic Reporting and VNC server technologies installed on the remote systems.

  • Resource tracking and simple configuration. All users of the remote sessions allocate the sessions using web pages generated by the Nexus server. As such Nexus can track session allocations and exert control over the remote rendering resources via a common database.

  • Proxy authentication and authorization. The remote session system exploits the authentication and authorization system in the Nexus server.

  • WebSocket interface for data tunneling. The system implements a websocket-based transport system that utilizes existing socket system used by the NGINX instance. It also supports SSL for encrypted connections.

Note

All of the files used in examples here can be found in the Ansys Dynamic Reporting distribution as:

v242/CEI/nexus242/django/utils/remote/config

To enable embedded remote sessions, the "Enable external session" option must be enabled. There are two types of remote sessions.

  1. Built-in local EnSight and EnVision sessions. These are associated with file data item filename extensions. For example an uploaded .evsn file will automatically be associated with EnVision. These sessions will run on the same system as the nexus server and require no specialized configuration.

  2. Externally specified configurations. These are specified in the file 'external_services.json' file that is placed in the database directory (the same directory as the view_report.nexdb) file.

Configuration ('external_services.json') File#

The first step in the configuration is to consider what types of remote rendering solutions one wants to provide access to.

In this example, we will focus on providing access to a software rendering vncserver-based configuration. Included in the distribution is a simple example that leverages a "start/stop" script running on remote nodes. That example uses an instance of the x11vnc application to provide VNC access to a hardware accelerated X11 server (see the scripts start_x11_server.sh, stop_x11_server.sh, x11vnc_desktop_session.py for an example of how this type of configuration can be realized).

The Nexus remote rendering system utilizes a configuration file in JSON format. The file describes a Python dictionary that contains descriptions of all of the available session types. An example might be:

{
   "Local Software Session": {"script": "desktop_session.py", "count": 2,
      "options": {"sizes": ["12080x1024", "1600x1200"], "display_base": 100}},
   "Cluster Node Session": {"script": "x11vnc_desktop_session.py", "count": 1,
      "options": {"sizes": ["1600x1200"], "group": "ClusterRendering", "host": "n8"}}
}

This configuration file defines a single Python dictionary with multiple keys (e.g. "Local Software Session"). Each key is the name of a type of session. The value of each session key is a Python dictionary. There are three required keys in each session dictionary. These include:

  • script: the name of a Python script file responsible for creating an object that can start and stop a session.

  • count: the maximum number of simultaneous instances of this session type

  • options: a dictionary of optional data items that can be used by Nexus to customize the web interface and any additional data items that can be used by the session instance

Each type of session must provide the name of a Python "script" file. This file must create an instance of a Python object (a subclass of RemoteServiceScript) that is responsible for starting and ending a session. There can be multiple instances of each session type active at the same time. This is limited with the "count" key which specifies the maximum number of simultaneously allowed sessions. When a session of a given type is started, an index number running from zero to this number minus one will be passed to the Python code. The code should use this number to ensure that each session uses non-conflicting resources (e.g. port numbers, node allocations, graphics cards, etc).

Additional pieces of data can be passed via the "options" object. The option dictionary is passed to the RemoteServiceScript creation method as 'common_options' and by default is stored as the _common_options attribute on the RemoteServiceScript subclass instance. The user is encouraged to add any customization options to this dictionary.

The Nexus system uses two keys to configure the HTML page it presents for selecting sessions. The first is 'sizes'. This should be a list of strings that are displayed in the pulldown menu used to start the session. It defaults to a list of common window sizes.

Image

The value selected for sizes is passed in the "options" dictionary to the RemoteServiceScript.start() method.

The Nexus system will also look for the "group" key in the options dictionary. In the example above, this key has been set to the value "ClusterRendering" for instances of the "Cluster Node Session" session type. If the "group" key is set to the name of a Nexus administration group, the session type will only be made available to users who are members of that specific group. In the example, if you are not a member of the "ClusterRendering" group, you will not be allowed to create "Cluster Node Session" sessions.

Session Lifecycle Python Script#

The "script" file is responsible for actually created and deleting a session. It takes the form of a Python script that creates instances of the core session lifecycle class. Taking a deeper look at the file "desktop_session.py" (which should be located in the same directory as the configuration JSON formatted file):

# Simple example remote service. The loader will call a method to
# realize the services associated with a specific service name.
# All services must subclass RemoteServiceScript.

from nexus_remote_service import RemoteServiceScript
import subprocess
import time

# Launch a vnc server (tightvnc) and run an optional command in the token json map file

class SimpleVNC(RemoteServiceScript):

   def __init__(self, *args, **kwargs):
      super(SimpleVNC, self).__init__(*args, **kwargs)

   def display_base(self):
      return self._common_options.get("display_base", 100)

   def start(self, token, timestamp=time.time(), options=dict()):
      username = options.get('username', '')
      size = options.get('size', '1600x1200')
      cmd = ["vncserver", "-depth", "24", "-geometry", size, ":"+str(self.display_base()+self._index)]
      try:
         print("SimpleVNC start: {} {}".format(self, cmd))
         code = subprocess.call(cmd)
         if code != 0:
            return False
      except:
         return False
      self.set_host_port("localhost", 5900+self._index+self.display_base())
      return super(SimpleVNC, self).start(token, timestamp=timestamp, options=options)

   def stop(self):
      cmd = ["vncserver", "-kill", ":"+str(self.display_base()+self._index)]
      try:
         print("SimpleVNC stop: {} {}".format(self, cmd))
         code = subprocess.call(cmd)
      except:
         pass
      return super(SimpleVNC, self).stop()

def realize_service(name="", count=1, index=0, common_options=dict()):
   print("Realizing SimpleVNC service: {} {} {} {}".format(name, count, index, common_options))
   return SimpleVNC(name, count=count, index=index, common_options=common_options)

realize_service() Startup function#

The Nexus core will import this file and call the function realize_service() with information gleaned from the JSON configuration file. The name will be the session type name (the top level key in the JSON file). The count and common_options keyword values will also have come directly from the JSON file, "count" and "option" keys respectively. realize_service() will be called once for each of the instances that may be legal. This for count=3, it will be called with index=0, index=1 and index=2. realize_service() must respond with an instance of a subclass of the RemoteServiceScript class. This subclass must at least implement the start() and stop() methods. All other methods are optional.

RemoteServiceScript.start() Method#

The start() method is called when a session has been authorized, authenticated and is ready to begin (e.g. an upstream entity has requested data over a websocket). In the example, the start() method creates an instance of 'vncserver' using the 'size' option selected in the Nexus web page. It also selects a port number using a base port number specified in the JSON configuration file and the index of this session instance. In a production environment, it can use the authenticated/authorized 'username' from Nexus to select a user target for the session. The start() method must call set_host_port() to set the hostname and port over which the processes it created (vncserver in this example) will be accepting VNC connections. The Nexus system will automatically tunnel this port over the websocket interface and apply any selected SSL encryption to the stream. If the operation fails, the function must return False.

RemoteServiceScript.stop() Method#

The stop() method is called after all active connections to a specific session instance have closed their connections (e.g. the browser or the specific tab is closed). It can also timeout. It will only be called if start() had previously been called. In our example, it simply calls vncserver -kill with the proper port specification for the instance.

Notes and Limitations#

  • The Remote Session system works by the Nexus core providing authentication and authorization. From that information, it generates a private cookie for the allocated session and serves these up via REST from the websocketserver.

  • The system works by Ansys Dynamic Reporting generating a web page with an embedded URL containing the private cookie. This cookie is passed to the websocketserver service when the JavaScript VNC server is realized. Thus, care should be taken to ensure that the transmission of the web page be protected by encryption. In order for the system to be secure, it is strongly recommended that SSL be used to access the NGINX server for all browser connections. The Nexus server will honor this encryption.

See the Known issues & limitations section for additional notes.