Skip to content

Instantly share code, notes, and snippets.

@CalebEverett
Last active March 29, 2023 15:04
Show Gist options
  • Save CalebEverett/bed94582b437ffe88f650819d772b682 to your computer and use it in GitHub Desktop.
Save CalebEverett/bed94582b437ffe88f650819d772b682 to your computer and use it in GitHub Desktop.
Lxd api example: lxc exec and operations websocket via nodejs
const fs = require('fs')
const WebSocket = require('ws');
const wsoptions = {
cert: fs.readFileSync('../../.config/lxc/client.crt'),
key: fs.readFileSync('../../.config/lxc/client.key'),
rejectUnauthorized: false
}
var ws = new WebSocket('wss://127.0.0.1:8443/1.0/events?type=operation', wsoptions);
ws.on('open', function open() {
console.log('open for notifications')
});
ws.on('error', (error) => {
console.log(error)
});
ws.on('message', function(data, flags) {
var buf = Buffer.from(data)
console.log(JSON.stringify(JSON.parse(data.toString()), null, 4))
});
const https = require('https');
const fs = require('fs');
const WebSocket = require('ws');
const options = {
method: 'POST',
host: '127.0.0.1',
port: 8443,
path: '/1.0/containers/lxd-websock/exec',
cert: fs.readFileSync('../../.config/lxc/client.crt'),
key: fs.readFileSync('../../.config/lxc/client.key'),
rejectUnauthorized: false
}
const body = JSON.stringify({
"command":["/bin/bash"],
"environment":{"MY_KEY":"my_value"},
"interactive":true,
"wait-for-websocket":true
})
const req = https.request(options, res => {
res.on('data', d => {
const output = JSON.parse(d);
const wsoptions = {
cert: options.cert,
key: options.key,
rejectUnauthorized: false
}
const ws = new WebSocket('wss://' +
options.host + ':' + options.port + output.operation +
'/websocket?secret=' + output.metadata.metadata.fds['0'],
wsoptions
);
ws.on('open', () => {
console.log('connection opened');
ws.send('printenv \r', { binary: true }, () => {
setTimeout(() => ws.send('exit \r', { binary: true }), 100);
setTimeout(() => process.exit(0), 200);
});
});
ws.on('error', error => console.log(error));
ws.on('message', data => {
const buf = Buffer.from(data);
console.log(buf.toString());
});
});
});
req.write(body);
req.end();
req.on('error', (e) => {
console.error(e);
});
@CalebEverett
Copy link
Author

CalebEverett commented May 3, 2016

Summary

This is a quick example of how to use the LXD api to submit an exec command to a running container and connect to the operations websocket endpoint to interact with the command:

  1. Submits a command of /bin/bash with an environment variable to the exec endpoint.
  2. Gets back the operation url and websocket secret and opens up a websocket connection at the websocket operations endopoint.
  3. Sends a command of printenv.
  4. Gets the resulting message back, decodes it to a string and logs it to the console.
  5. The events-websock.js file can be run in another terminal window to see notifications.

Reminders

Before using the api you have to add your certificate to the server - see curl over the network (and client authentication).
The rejectUnauthorized: false key is necessary to establish both the https and wss connections in order to prevent them from choking on the self-signed certificate.
The { binary: true } option is necessary for sending commands via the websocket.

Resources

LXD Api Doc
Directly interacting with the LXD API
ws: a node.js websocket library
The WebSocket Protocol
Writing WebSocket client applications
websocketd

@lcherone
Copy link

Thanks for this,

If you're connecting to local LXD with node, you don't need to setup certificates if you use.

require('child_process').exec

and use it to call this little gem:

lxc query -X POST -d '{"command":["/bin/bash"],"environment":{"MY_KEY":"my_value"},"interactive":true,"wait-for-websocket":true}' /1.0/containers/c1/exec

That will the give you the operation id and the secret which is required for the websocket.

@turtle0x1
Copy link

turtle0x1 commented Jan 1, 2019

Your the best for this ❤️ I wasted some much time and went through so many web socket libraries ❤️

@babandiaye
Copy link

Hello guys
I want to connect my container LXD to xterm.js for a terminal bash on my website
my IP server LXD is 192.168.1.207:8443
my certificates path /var/www/html/plateforme/client.crt and client.key

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment