Opd

Opd is the operational mode command executor for the DANOS system. This service provides a mechanism to model available operational mode commands, provide help context for the modeled commands, and execute the modeled commands in the appropriate environment.

Modeled operational mode commands are defined in a YANG based DSL or in a legacy template language. Contextual help for the CLI is generated from this command tree model. The contextual help is rendered via opc querying the opd API as the user browses the CLI.  These modeled commands map the desired command to a script which implements the command. Opd runs these scripts in an appropriate environment when the user requests the modeled command.

Opd runs as a superuser on the system and can exec commands as a privileged user or as the user requesting the command depending on the way it is modeled. Opd provides Authorization and Accounting for the commands which are requested via its interface. Opd is treated as a trusted entry point application and sets the loginuid of the processes it executes to the requesting user. 

Some commands are modeled as "local" commands and execute in the user's local shell. This is only useful for things that effect the shell environment directly. One of these "local" commands is "configure" which creates a subshell with the configuration mode environment.

Command Execution

When a command typed at the operational mode shell matches one of the aliases for the modeled top level commands an opc instance will be invoked which does the following:

  1. Decides which command or commands need to run based on command expansion and command regexp substitution operations.

    1. Commands are expanded to the full command from an abbreviated command. If a command is not found which can unambiguously be executed an error is returned.

    2. The variable fields in a command (those that may refer to a user defined string) are then regexp matched against the allowed field. This may yield more than one command that need to be executed in sequence.

  2. Sets up a PTY and the appropriate terminal context on the user's TTY to allow proper terminal interaction.

  3. Starts copiers to copy bytes between the user's TTY and the PTY to which the requested command will read and write.

  4. If the command is run in the foreground, starts a window change terminal resizing process by listening for SIGWINCH signals and getting the size from the TTY.

  5. For each command to be executed, sends a "run" request to opd via the opd API containing the PTY path that is to be used for the command's stdin, stdout, and stderr when starting the command.

When opd receives a "run" request it will invoke the script associated with the modeled command in the operational command tree with the passed PTY as stdin, stdout, and stderr.

The following diagram demonstrates the relationship between the TTY, opc, the PTY, opd and the requested command:

Internals

Internally opd consists of several processes.

  • "Server" listens for connections and spawns a goroutine for each connected client.

  • "Reloader" which tells opd to reread the data-model for the operational command tree and the authorization/accounting configuration.

  • "Auth" with listens for and responds to authorization and accounting requests from the "Handlers" on a set of Go channels.

    • "Auth" calls the AAA Plugin API to work with a given AAA protocol.

    • "Auth" implements the local ruleset for command authorization.

  • "Handler" which processes requests for each connected client.

    • "Handlers" implement the interface for the Opd API.

Opd uses JSON RPC as the wire encoding for its request and response model. By default this listens on a given socket. If running in a systemd environment (as will be the case on DANOS) the socket is passed via the systemd activation interface.

Related source code

https://github.com/danos/opd/tree/master/cmd/opd

https://github.com/danos/opd/tree/master/cmd/opc