Command line interface
Although not strictly a client library as such, the tdx Volt command line interface (CLI) exposes several aspects of the core tdx Volt API for use in shell scripts and other terminal-based processes. This, in combination with the tdx Volt wire
functionality, provides opportunities for useful and succinct workflows.
The tdx Volt CLI can also act as a server, and can be daemonised to run one or more Volts in the background.
The tdx Volt CLI supports several commands, and the arguments and syntax of each command varies. The basic format to invoke a command is:
./volt <command> [options]
Help is available for each command using the -h
or --help
switch, for example:
./volt create --help
tdx Volt management commands
The commands in this section relate to tdx Volt management tasks, such as creating and running Volts.
battery options
There are some options that are common to the tdx Volt management commands, including those to do with configuration of the Battery in which the tdx Volt is contained.
The Battery name can be configured using the -b
switch. If this switch is omitted, the default Battery is used.
For example, to create a tdx Volt in a Battery named Household
:
./volt create Alice -b Household
Use the --bp
switch to specify an encryption passphrase and create a secure Battery:
./volt create Alice -b Household --bp foobar
As above, but using --bp .
to request a passphrase prompt:
./volt create Alice -b Household --bp .
Note that once an Battery is encrypted, the passphrase will be required for any subsequent tdx Volt command. For example to start a tdx Volt that is stored in a passphrase-protected Battery:
./volt run 449a3385-f380-41f7-bd0a-e60caaa403cb -bp foobar
create command
The command to create a Volt.
In the following example, the tdx Volt will be created in the default Battery, with no passphrase protection or encryption on either the Battery storage or the tdx Volt itself.
./volt create "Alice's laptop"
To avoid having to copy and paste the UUID when subsequently referring to the tdx Volt, you can give it an alias using the -a
switch:
./volt create "Alice's laptop" -a alice
The alias can be substituted for the UUID, by prefixing it with @
:
./volt run @alice
Create a secure Volt
Use the -p
switch to specify a passphrase that will be used to encrypt the tdx Volt root key and storage.
By default, the tdx Volt will auto-generate a new key at creation and encrypt it with the given passphrase. The tdx Volt will not store the passphrase so you must remember it.
It is recommended to use a phrase rather than a single word for the passphrase, for example "I like cheese".
./volt create "Alice's laptop" -p secret
Use a period with the passphrase switch (-p .
) to force the CLI to prompt for the passphrase rather than include it explicitly in the command line.
./volt create "Alice's laptop" -p .
There is currently no way to recover or reset the **tdx Volt** passphrase so if you lose it you will not be able to access the Volt.
Create a tdx Volt using a fixed host
By default when a tdx Volt is created its certificate is bound to the current (or first) ipv4 network interface address. If you would like to bind a tdx Volt to a specific IP address or domain name use the host
and port
command line switches.
./volt create "Alice's server" --host aliceserver.com --port 40725
Create a tdx Volt with a file-based key
By default the tdx Volt key is stored with the tdx Volt configuration in the Battery. If the Battery is encrypted with a strong passphrase this is a fairly safe option.
Alternatively you can create a tdx Volt using a key stored on the local file system.
./volt create "Alice's laptop" -k /path/to/key/file
If /path/to/key/file
does not exist it will be created.
If the key is encrypted (recommended) you can specify or prompt for the passphrase using the -p
switch as described above.
./volt create "Alice's laptop" -k /path/to/key/file -p .
See the key strategy section for more information.
For full usage information:
./volt create --help
run command
Use the run
command to start a Volt.
This command can be used to daemonise an instance of a Volt, using an init.d
script or similar.
To run a tdx Volt that is in the default Battery and is not passphrase-protected:
./volt run f902f0f7-b9b7-4d2a-b05a-2d4e76a16ded
To run a passphrase-protected Volt, use the -p .
option to prompt for a passphrase:
./volt run f902f0f7-b9b7-4d2a-b05a-2d4e76a16ded -p .
If the tdx Volt is not in the default Battery, specify the path to the Battery using the -l
option:
./volt run f902f0f7-b9b7-4d2a-b05a-2d4e76a16ded -p . -b Household
For full usage information:
./volt run --help
config command
The config
command can be used to show the available tdx Volt configurations, or see the detail of a particular tdx Volt configuration.
To list all Volts in the default Battery:
./volt config
To list all Volts in a given Battery:
./volt config -b Household
To view the full configuration for a given Volt, specify the tdx Volt id or alias:
./volt config @alice
For full usage information:
./volt config --help
Client commands
The commands in this section are classed as tdx Volt client commands, and as such they require client credentials in order to authenticate with the target Volt.
There are two ways to specify the client credentials, either via a well-known file named volt.config.json
, or using a custom file name and passing it via the command line switch -c
.
See the connection section for more details about client credentials.
The following examples assume that the client credentials have been placed in the volt.config.json
file.
auth command
The auth
command can be used to create a new client identity and corresponding configuration file.
Specify the DID or URL of the tdx Volt to authenticate against:
./volt auth did:volt:4801dd12-410d-46d4-84f8-efb0ba609085
You can also override the default configuration file:
./volt auth did:volt:4801dd12-410d-46d4-84f8-efb0ba609085 -c bob.config.json
Alternatively, you can specify the URL of the tdx Volt to authenticate with rather than the DID:
./volt auth http://localhost:58213 -c carol.config.json
If your client configuration session has expired, you can use the --renew
switch to renew the session:
./volt auth --renew
For full usage information:
./volt auth --help
download command
Download a file or folder from the tdx Volt to the local disk:
./volt download ./shares/images volt-downloads
In the example above, the .
prefix of ./shares/images
indicates that the path is relative the ‘home’ folder of the client.
To specify a path relative to the root of the tdx Volt itself, use a /
prefix:
./volt download /documents/reports volt-downloads
For full usage information:
./volt download --help
upload command
Upload a file or folder to the Volt.
./volt upload ~/Documents/images ./shares
The .
prefix on ./shares
indicates the target resource is relative to the ‘home’ folder of the client.
To upload to a resource relative to the root of the tdx Volt itself, use a /
prefix:
./volt upload ~/Documents/images /documents/images
For full usage information:
./volt upload --help
list command
List resources on the tdx Volt (similar to ls
or dir
shell commands).
./volt list ./shares
For full usage information:
./volt list --help
terminal-server command
The terminal-server
command can be used to start a terminal server that allows others to remotely access the local machine.
To create and/or start a terminal server:
./volt terminal-server
If the configuration file doesn’t contain a service_id
field, a new service will be created and the service_id
will be written to the configuration file. Otherwise, the existing service will be started.
All Volts support a built-in terminal server that provides access to the Volt local machine. This requires explicit activation in the Volt settings via the fusebox, as well as access permission for command-invoke
.
For full usage information:
./volt terminal-server --help
terminal-client command
The terminal-client
command can be used to connect to a terminal server running on a remote machine.
You will need command-invoke
permission on the terminal-server service in order to be able to connect to a terminal server.
To connect to a terminal server, specify the service id or alias:
./volt terminal-client 994e51f3-4ffa-4fc0-9d50-be59db92ebe5
To connect to the default (built-in) terminal of a Volt, use the __terminal-server
alias:
./volt terminal-client @__terminal-server
For full usage information:
./volt terminal-client --help
whoami command
The whoami
command can be used to display details of the current client configuration.
./volt whoami
As with other client commands, you can specify a custom configuration file using the -c
switch:
./volt whoami -c bob.config.json
For full usage information:
./volt whoami --help
wire command
Subscribe or publish to wire resources.
publish
To publish to a wire, specify the wire identifier or alias:
./volt wire @sensor-feed
The wire data is read from STDIN
. This enables flows such as:
curl www.google.com | ./volt wire bcc778cd-04b0-4e5e-803c-dcca143790e1cat somefile | ./volt wire bcc778cd-04b0-4e5e-803c-dcca143790e1
subscribe
To subscribe to a wire, add the -s
switch to the command line:
./volt wire 9c797959-eafe-4d2a-8005-1e5ef66c29ac -s
All wire data will be written to STDOUT. This enables flows such as:
./volt wire -s bcc778cd-04b0-4e5e-803c-dcca143790e1 | wire-data.log
For full usage information:
./volt wire --help
wire-remote command
The wire-remote command can be used to control a locally running command or executable remotely via wires.
The default command is /bin/sh
, but you can specify a different command using the --cmd
switch.
./volt wire-remote @stdin @stdout
The example above will start a new shell and connect the STDIN and STDOUT of the shell to the wires specified. This means that all data published to the @stdin
wire will be sent to the STDIN of the shell, and any data written to the STDOUT of the shell will be published to the @stdout
wire.
To use a command other than /bin/sh
, specify the command using the --cmd
switch:
./volt wire-remote @stdin @stdout --cmd /bin/node
As with other client commands, you can specify a custom configuration file using the -c
switch:
./volt wire-remote @stdin @stdout -c bob.config.json
For full usage information:
./volt wire-remote --help
Utility commands
logger command
Split data arriving on a wire or STDIN
into files on the local disk.
This command was developed for use with the Protobuf Database Sync utility, but it may be useful in other scenarios.
The logger
command listens for incoming data on a Volt wire or STDIN
, splitting the input into multiple files of a
configured maximum size in a configured folder. It makes no attempt to interpret the incoming data.
If a header is given
as part of the tdx Volt Logger configuration it will populate and write a ProtobufSyncConfigurationHeader
message to the start of each file it creates.
Once a file reaches the configured size (logFileSize
) it will be moved to the ingestion folder, where it
will get picked up by the protoDbSync process if one is running. The logger will then create a new file to continue
logging the incoming data.
This enables scenarios such as:
# Continuously pipe data from a producer, splitting it into log files.> fs20PacketProducer | volt logger -c fs20.logger.json
# Continuously pipe data from a tdx Volt Wire (grpc stream), splitting it into log files.> volt logger -c zwave.logger.json -w d1cc1560-9b58-4bdf-a2cf-7d65a2db0c01
# Load data from a URL.> curl https://somedata.endpoint | volt logger -c snapshot.logger.json
An example logger configuration when reading from STDIN
is shown below.
{ "logger": { "headerId": "tcpdump-logger", "headers": [ { "messageName": "TCPDumpPacket", "messageProto": "syntax = \"proto3\";\n\npackage tranforms;\n\nmessage TCPDumpPacket {\n string timestamp = 1;\n string source_mac_address = 2;\n string source_manufacturer_id = 3;\n bool is_broadcast = 4;\n bool is_arp = 5;\n string target_mac_address = 6;\n string target_manufacturer_id = 7;\n string ether_type = 8;\n string unknown_1 = 9;\n int32 length = 10;\n string source_address = 11;\n string target_address = 12;\n string payload = 13;\n}\n", "name": "header0", "tableName": "tcpdump" } ], "logFileExtension": "pdat", "logFilePath": "./logs", "logFilePrefix": "tcpdump-log-", "logFileSize": 64000 }}
If reading from a wire, the configuration should include details of a standard client connection, as shown below. The credentials given should have subscribe
access to the source wire.
{ "logger": { "headerId": "tcpdump-logger", "headers": [ { "messageName": "TCPDumpPacket", "messageProto": "syntax = \"proto3\";\n\npackage tranforms;\n\nmessage TCPDumpPacket {\n string timestamp = 1;\n string source_mac_address = 2;\n string source_manufacturer_id = 3;\n bool is_broadcast = 4;\n bool is_arp = 5;\n string target_mac_address = 6;\n string target_manufacturer_id = 7;\n string ether_type = 8;\n string unknown_1 = 9;\n int32 length = 10;\n string source_address = 11;\n string target_address = 12;\n string payload = 13;\n}\n", "name": "header0", "tableName": "tcpdump" } ], "logFileExtension": "pdat", "logFilePath": "./logs", "logFilePrefix": "tcpdump-log-", "logFileSize": 64000 }, "client_name": "CLI", "crypto": { "cert": "-----BEGIN CERTIFICATE-----\nMIIDWzCCAkOgAwIBAgIEQ7J4qTANBgkqhkiG9w0BAQsFADBxMQswCQYDVQQGEwJH\nQjEUMBIGA1UEBwwLU291dGhhbXB0b24xGjAYBgNVBAoMEW5xdWlyaW5nTWluZHMg\nTHRkMTAwLgYDVQQDDCdjYS4zODAzYzIzOS1mZmM2LTQwYTMtYjg1Yy0xZGE3OTg5\nNDVjM2MwHhcNMjIxMDI1MDcyNDM2WhcNMjMxMDI1MDcyNDM3WjBuMQswCQYDVQQG\nEwJHQjEUMBIGA1UEBwwLU291dGhhbXB0b24xGjAYBgNVBAoMEW5xdWlyaW5nTWlu\nZHMgTHRkMS0wKwYDVQQDDCQ1NzZkM2YwNy0wYWFiLTRjZWQtYjEwZi0wODUyMjBj\nMmIxZmYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmVwOOkfIN95Sr\nmqKGPUTNdfFbuz7R0SIXzTuAI+tOiBmhH3QRadSOq58/3OgozW/xJ1jaiSGJKmi+\nMm44dNsCdi5O5HJboBER7A6FKn+R0YWJGmeT9jfzpK/ygUfF2qvRZ622odSVUm+m\n04DP1ZJya22wy9Y3SNvpLI1BqGsWUdjuSyzog246Tt0Dt3OC+VvG3xWCPJdgXyvq\nB1FuLm6l6F60soo+MJ6lWEcZ/oXUdeqTEac56+H8c6ol5raru0oJlawA6vXCfN6h\nRx+VjeFhSBBSIa7b99+7yBLa7xLzpX/Eb2mccUTMSenHG/TxnW5ftbzrXKLEhlDx\n0/SFRW6dAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAKbVpTl+ZIHgSSzOntuo9Ezd\nu3mKx/xWS+RPmXnHU9KsZjCJN00F84pf/a7SNlUJv/Mwob8gTpawVByoFjl6iV7o\nZJc+1op9aYHlmrqumCXairY//dlsGXJ2F7Wl2dqckn+Wqk4Jgk83NucAl5JgxLmR\nB9UwL81pzeXHjSPkaF17BzAxB42fIpDJ1Uies/4BjjwFWn2ebSyC/z3flB2YBF3c\nS1Gak8I56iyTCdjT0LkUoMVHNxFXg6xsorbBN4qy5CM5V5rbTJmZBYzZNIlTusBA\ngqPDsgRCNYGxsbDVB71thOSKzR0mltx2ICqV360MET0II8P3WYS4o7aFegk3OIY=\n-----END CERTIFICATE-----\n", "client_id": "576d3f07-0aab-4ced-b10f-085220c2b1ff", "key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCmVwOOkfIN95Sr\nmqKGPUTNdfFbuz7R0SIXzTuAI+tOiBmhH3QRadSOq58/3OgozW/xJ1jaiSGJKmi+\nMm44dNsCdi5O5HJboBER7A6FKn+R0YWJGmeT9jfzpK/ygUfF2qvRZ622odSVUm+m\n04DP1ZJya22wy9Y3SNvpLI1BqGsWUdjuSyzog246Tt0Dt3OC+VvG3xWCPJdgXyvq\nB1FuLm6l6F60soo+MJ6lWEcZ/oXUdeqTEac56+H8c6ol5raru0oJlawA6vXCfN6h\nRx+VjeFhSBBSIa7b99+7yBLa7xLzpX/Eb2mccUTMSenHG/TxnW5ftbzrXKLEhlDx\n0/SFRW6dAgMBAAECggEBAIdTp1soNWtTjyqFZdAcrIsTd0cP8S22HSyMFepMTrXX\nWDKTalR4ayufSLImQOJhML9bKZixlA0J6alDUhSwTTWVfFtG1BrjAMA58h440wyJ\nD0DZsIbZ++9GframowO+waZd2SAKTO8m4BszW0q7EKfx6o25aBAWQINVcZ6HLIg8\nwphpPaZJzMZCnSssAqA26x+yHzyiGBwECuKM382+jjTcasnxh5zh7JvxtWyOXjQM\n3EpCFLlGKCz2UWAxDThoyCqGVIVtkBR2b230TB5mjeI1slDy2iKHDfYXy+AWcDku\naYfQBLo96Fr2jPIBOkRXv91KMsyzNukrYwZzeRrN38ECgYEA0Uukd1F/8Vg0Ie9e\nHh5kXFOn9cB3CU+v9djF9LYxjrw3h/E74AT4ZuPl1PRyDXE6OUWWa7ouH0NhmBUU\nz7U6tlRdeW65S1aUoCkRzGB1nU9LQ0tz3lUKQ3P6SMusqErbJdLiCkXBCapTYr8n\nfliRwKU4CKf4wdH32hRlRs4CaLUCgYEAy3V2HnutXXteDvhhS5PqjVF8BPYq5h84\n5p70bsnCwkz9bDC7WJQwU6b9a4nofWhp3uGwSG/fji5MeRJzSf05Y5KUeZ0Lcvcn\nhGKpOGwE9BDlEedSAchYl6zdTrjo78ZOZ7QHjiuH0dgEc7A+E6S49Z6OaZtos37r\nKx6CAtVaJ0kCgYBT5p7ntiQz+8fqUqrIKCbTXDXYrm8JrIg9Zcj1cJQtRAZ+2JXI\nGDX8CR/5XoTaHqnYi6zhQqF6puhYrxrIqT4AGZHfPCPLr8mk6tHXvFNp3H+vWm/4\nkN6sa7HJvNxaGqf/Yap7s7rOxRjoXPjYDWlgcNslnTB7glB5e/OdjrgogQKBgD/6\nL6pmOZ2rrWgHspCRcq/9b4If5l12c+4RDcvIpfVzQD1FFaRE9O1ZFVc7hl/o9WGg\nlk4w35tV87YelyIs/l7RON8FAxSjo0l9vLiBPw2AQofetWraFQGc2fpnKtg7A2yY\nr8eE6LCTvNKkGOEUaxTRRvbuZ34J6ukkLr21WSQBAoGAeZJfkWCeX+14Qorb48Oq\nS32hYEzxYj2v3/4xUUqh9x9l1OsIUXWsc4c0Ya/D9bnoC3DQZFbwI7dtjhXRfwqj\nXSpFJv7+xq67hEnL2L5Y9s+HslpnM7uko+1bqrkMQ+XWcVSgqnWgQSPsbFia/FdL\npq+eQLE2/TcqWaM7hCWxjoc=\n-----END PRIVATE KEY-----\n" }, "volt": { "ca_pem": "-----BEGIN CERTIFICATE-----\nMIIDojCCAoqgAwIBAgIENzfzHjANBgkqhkiG9w0BAQsFADBxMQswCQYDVQQGEwJH\nQjEUMBIGA1UEBwwLU291dGhhbXB0b24xGjAYBgNVBAoMEW5xdWlyaW5nTWluZHMg\nTHRkMTAwLgYDVQQDDCdjYS4zODAzYzIzOS1mZmM2LTQwYTMtYjg1Yy0xZGE3OTg5\nNDVjM2MwHhcNMjIxMDA2MDY0MTQ5WhcNMjMxMDA2MDY0MTUwWjBxMQswCQYDVQQG\nEwJHQjEUMBIGA1UEBwwLU291dGhhbXB0b24xGjAYBgNVBAoMEW5xdWlyaW5nTWlu\nZHMgTHRkMTAwLgYDVQQDDCdjYS4zODAzYzIzOS1mZmM2LTQwYTMtYjg1Yy0xZGE3\nOTg5NDVjM2MwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC685OWXJgG\ndBcmOFd0bKGBbH+JCVscnL2UahdO2i1exxVT0buVhI5gsATbvoiYShz8Vqi5H+EX\nTACSBO1ojDMRT+tLvqx61vqFvwpA5iNcN2IpnA72pK5hklS5MBiUQ/R02kqCIX3D\nz0F2ZsWuGo2TWsMGrcCkR8a/1oCLwTa3oO9JZhXckzrYiQZyWWtRG7vmJXz1Enrh\nZ0pXPGa94H7Hrm/q+J6Uy5c1r/sRK5pJH79Z+sTZuM71ooGbMScKfVx/+bd70MWB\nQK1o1vMUjEBACzizietpLXgT8xBYw2QwMGiMZsj4LKiYvDiUrniL5yQlmHTIWI5g\n9v3soaZFp4LRAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD\nAgEGMB0GA1UdDgQWBBQaa1NBh69uMVMOsXKBA4cR/h57HTANBgkqhkiG9w0BAQsF\nAAOCAQEAteNPjx7+9SsnSOs+LE9DdbyvcOOpqbcfSH6PDMyQoNs5o+K+yCTe2GOy\nkB4BMJQq3d+I17ivisQI1/bS6Pn364aO8B+9KeWCQq5MteoLJF4pscM5+R3sxkat\nPmWHHTum/lE1XSG5V2ytaXZvML/spWB7kSKMw7uOWjvr0dZ1Nq+dN1hmLb6p72Ir\n5Gwl2Byqvofet8/Dqx+hMXw5I+v9b3XXzay1mDhL40zgC/WYBsG0nJJwqHmdS8IN\nQrlxJ3fk2HCfQFnVue1h/2LHLM+MnEExdULB/BNp7MS1VeQ135eXfkhHd2fl7LKf\nwBSLRoniDb1gvtKSHuAZ5PaJELswJg==\n-----END CERTIFICATE-----\n", "challenge_code": "w6uP8Tcg6K2QR905Rms8iXTlksL6OD1KOWBxTK7wxPI=", "id": "3803c239-ffc6-40a3-b85c-1da798945c3c", "address": "192.168.1.139:40265" }}
STDIN logger performance
Reading asynchronously from STDIN
is surprisingly difficult. The method used by the logger command involves a background
thread that reads data from STDIN
one byte at a time, and when the accumulated data reaches the configured log size the
data is flushed to disk.
On its own this approach causes problems whereby a flush might occur in the middle of an incoming packet, thus breaking the protobuf binary format.
To guard against this, the Volt logger uses a second thread thread which is responsible for flushing the buffer, and will only do
so after 50ms of inactivity on STDIN
(the interval is configurable via the flushIdleInterval
property in the configuration file). As a consequence, the produced log file size may slightly exceed that configured in logFileSize
.
The flushing thread described above helps reduce the frequency of split packets, but they can still occur due to network latency or other timing blips on the incoming data. Fortunately the protoDbSync utility can recover from these split packets the majority of the time.
Support for more commands in the Volt CLI is coming soon...