Files

3.7 KiB

@vates/nbd-client

Package Version License PackagePhobia Node compatibility

Install

Installation of the npm package:

npm install --save @vates/nbd-client

Usage

This package provides a NBD client, in two flavors sharing the same protocol implementation (AbstractNbdClient): over the network, or over the standard streams of a NBD server run as a child process.

new NbdClient({address, exportname, cert, port = 10809})

Create a new nbd client connecting to a server over TCP.

NbdClient is also exported as NbdTcpClient.

import NbdClient from '@vates/nbd-client'
const client = new NbdClient({
  address: 'MY_NBD_HOST',
  exportname: 'MY_SECRET_EXPORT',
  cert: 'Server certificate', // optional, will use encrypted link if provided
})

await client.connect()
const block = await client.readBlock(blockIndex, BlockSize)
await client.disconnect()

new NbdStdioClient({command, args, exportname})

Create a new nbd client talking to a server through its standard streams, like nbdkit --single or any server reading its queries on stdin and writing its answers on stdout.

The process is spawned by connect() and stopped by disconnect().

import { NbdStdioClient } from '@vates/nbd-client'
const client = new NbdStdioClient({
  command: 'nbdkit',
  args: ['--single', '--exit-with-parent', '--read-only', 'file', '/path/to/disk.raw'],
  exportname: '', // optional, the default export of the server
})

await client.connect()
const block = await client.readBlock(blockIndex, BlockSize)
await client.disconnect()

There is no TLS here: the transport is a pair of pipes, there is nothing to encrypt.

readBlock() retries on error, and a retry reconnects: with this client that means killing the server and spawning a new one, so the command must be restartable and must serve the same content on each run.

getMap() is not implemented, since nbdinfo needs either an URI or a server supporting systemd socket activation: compute the map on the caller side and pass it explicitly, for example new NbdDisk(infos, blockSize, { dataMap }).

The tail of the server stderr is available as client.stderr and attached to the errors raised when the server dies unexpectedly.

Writing another client

Subclass AbstractNbdClient and implement the transport:

  • _openTransport(): required, returns { readable, writable }, called on every (re)connection.
  • _secureTransport(transport): optional, called during the handshake, the only place where the transport can be upgraded (NBD_OPT_STARTTLS).
  • _closeTransport(transport, lastMessage): optional, must hand over lastMessage (NBD_CMD_DISC) before closing.
  • _destroyTransport(transport): optional, forceful cleanup, must not throw.
  • getMap(signal): optional, the base implementation rejects with the code NBD_MAP_UNSUPPORTED.

Any extra property set on the transport object is passed back to _closeTransport() and _destroyTransport().

Contributions

Contributions are very welcomed, either on the documentation or on the code.

You may:

  • report any issue you've encountered;
  • fork and create a pull request.

License

ISC © Vates SAS