Skip to content

Commit

Permalink
Create mechanism to read files from host /
Browse files Browse the repository at this point in the history
The supervisor needs to read some files from the host root since there
are no alternative interfaces that the host provides. These files are

- /etc/os-release to read the OS version
- /run/openvpn/vpn_status/active to check the VPN status

While we are working to introduce alternative interfaces for reading the
information provided by these files, the supervisor still needs a
backwards compatible way to get that info.

This PR uses the fact that the supervisor has access to the docker
socket to mount a file into a container and read the file from there.

Change-type: minor
  • Loading branch information
pipex committed Dec 20, 2022
1 parent a482174 commit 91775fc
Showing 1 changed file with 68 additions and 0 deletions.
68 changes: 68 additions & 0 deletions src/lib/host-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { spawn } from 'child_process';
import * as path from 'path';
import * as constants from './constants';
import { exec, exists } from './fs-utils';
import { PassThrough } from 'stream';
import { docker } from './docker-utils';

// Returns an absolute path starting from the hostOS root partition
// This path is accessible from within the Supervisor container
Expand All @@ -21,6 +23,72 @@ class CodedError extends Error {
}
}

/**
* This function is used to read a file from the hostOS
*
* This function launches a docker container with a mount into
* the hostOS root partition, and then reads the file from there.
* This is an expensive operation and should be used ideally never.
*
* TODO: remove this when the OS has a dbus API for reading the OS version
* and the VPN status
*/
export async function readFromRoot(
fileName: string,
encoding: 'utf8' | 'utf-8',
): Promise<string>;
export async function readFromRoot(fileName: string): Promise<Buffer>;
export async function readFromRoot(
fileName: string,
encoding?: 'utf8' | 'utf-8',
) {
const stdout = new PassThrough();

return new Promise(async (resolve) => {
const chunks: Buffer[] = [];
stdout.on('data', (chunk) => {
chunks.push(Buffer.from(chunk));
});

stdout.on('end', () => {
const buf = Buffer.concat(chunks);
if (encoding) {
resolve(buf.toString(encoding));
} else {
resolve(buf);
}
});

const [output] = await docker.run(
// TODO: use the supervisor image for this. We need first to get
// the image from the current container
'alpine:latest',
['cat', fileName],
stdout,
{
HostConfig: {
Mounts: [
{
type: 'bind',
source: fileName,
target: fileName,
readonly: true,
},
],
AutoRemove: true,
},
},
);

if (output.StatusCode !== 0) {
throw new CodedError(
`Failed to read ${fileName} from the hostOS`,
'ENOENT',
);
}
});
}

// Receives an absolute path for a file (assumed to be under the boot partition, e.g. `/mnt/root/mnt/boot/config.txt`)
// and reads from the given location. This function uses fatrw to safely read from a FAT filesystem
// https://github.com/balena-os/fatrw
Expand Down

0 comments on commit 91775fc

Please sign in to comment.