Skip to content

Commit

Permalink
Check existence of mountinfo and cgroup files
Browse files Browse the repository at this point in the history
  • Loading branch information
magarcia committed Nov 13, 2022
1 parent 26ce423 commit 1a68f49
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 21 deletions.
73 changes: 59 additions & 14 deletions server/lib/system/system.getGladysContainerId.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,28 @@ async function getGladysContainerId() {
if (!this.dockerode) {
throw new PlatformNotCompatible('SYSTEM_NOT_RUNNING_DOCKER');
}

let containerId = await getContainerIdFromCidFile();

if (containerId === undefined) {
// Not found in cidfile try on cgroup
containerId = await getContainerIdFromCgroup();
}

if (containerId === undefined) {
// Not found in cgroup try on mountinfo
containerId = await getContainerIdFromMountInfo();
}

if (containerId === undefined) {
throw new PlatformNotCompatible('DOCKER_CONTAINER_ID_NOT_AVAILABLE');
}

// we return the containerId trimed, just in case
return containerId.trim();
}

async function getContainerIdFromCidFile() {
try {
// We try if the cidfile exist in the container
await fs.promises.access(CIDFILE_FILE_PATH_IN_CONTAINER, fs.constants.F_OK);
Expand All @@ -21,8 +43,18 @@ async function getGladysContainerId() {
// we return the containerId trimed, just in case
return containerId.trim();
} catch (e) {
// if not, we get the containerId from the cgroup
const cgroup = await fs.promises.readFile('/proc/self/cgroup', 'utf-8');
// container id not found return undefined
return;
}
}

async function getContainerIdFromCgroup() {
const cgroupFile = '/proc/self/cgroup';
try {
// We try if the cgroup file exist in the container
await fs.promises.access(cgroupFile, fs.constants.F_OK);
// if yes, we read it
const cgroup = await fs.promises.readFile(cgroupFile, 'utf-8');
// String looks like this in cgroup v2 (Debian 11)
// 0::/system.slice/docker-2bb2c94b0c395fc8fdff9fa4ce364a3be0dd05792145ffc93ce8d665d06521f1.scope
// Or this in cgroup v1 (Debian 10)
Expand All @@ -41,20 +73,33 @@ async function getGladysContainerId() {
[, firstPart] = lineWithDocker.split('docker-');
// then, we remove .scope
[containerId] = firstPart.split('.scope');
} else {
const mountinfo = await fs.promises.readFile('/proc/self/mountinfo', 'utf-8');

if (mountinfo.indexOf('/docker/containers/') !== -1) {
const allLines = mountinfo.split('\n');
const lineWithDocker = allLines.find((line) => line.indexOf('/docker/containers/') !== -1);
[, containerId] = /\/docker\/containers\/(\w+)/gm.exec(lineWithDocker);
} else {
throw new PlatformNotCompatible('DOCKER_CGROUP_CONTAINER_ID_NOT_AVAILABLE');
}
}
return containerId;
} catch (e) {
// container id not found return undefined
return;
}
}

// we return the containerId trimed, just in case
return containerId.trim();
async function getContainerIdFromMountInfo() {
const mountInfoFile = '/proc/self/mountinfo';
try {
// We try if the mountinfo file exist in the container
await fs.promises.access(mountInfoFile, fs.constants.F_OK);
// container id not found return undefined
const mountinfo = await fs.promises.readFile(mountInfoFile, 'utf-8');
// String looks like this in mountinfo (Debian 11)
// 1077 888 179:2 /var/lib/docker/containers/83fa542c0b140e45e63ad7263c539ac08e2cbf7916894f1c51c3f016397b168e/hosts /etc/hosts rw,noatime - ext4 /dev/root rw
let containerId;
if (mountinfo.indexOf('/docker/containers/') !== -1) {
const allLines = mountinfo.split('\n');
const lineWithDocker = allLines.find((line) => line.indexOf('/docker/containers/') !== -1);
[, containerId] = /\/docker\/containers\/(\w+)/gm.exec(lineWithDocker);
}
return containerId;
} catch (e) {
// container id not found return undefined
return;
}
}

Expand Down
43 changes: 36 additions & 7 deletions server/test/lib/system/system.getGladysContainerId.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ describe('system.getGladysContainerId', () => {
beforeEach(async () => {
FsMock = {
promises: {
access: fake.resolves(null),
access: sinon.stub(),
readFile: sinon.stub(),
},
constants: {
Expand Down Expand Up @@ -128,12 +128,19 @@ describe('system.getGladysContainerId', () => {
});

it('should return containerId through cidfile', async () => {
FsMock.promises.access.withArgs('/var/lib/gladysassistant/containerId').resolves(null);
FsMock.promises.readFile.resolves('967ef3114fa2ceb8c4f6dbdbc78ee411a6f33fb1fe1d32455686ef6e89f41d1c');
const containerId = await system.getGladysContainerId();
expect(containerId).to.eq('967ef3114fa2ceb8c4f6dbdbc78ee411a6f33fb1fe1d32455686ef6e89f41d1c');
});
it('should return containerId through exec in mountinfo (Debian 11)', async () => {
FsMock.promises.access = fake.rejects();
FsMock.promises.access
.withArgs('/var/lib/gladysassistant/containerId')
.rejects()
.withArgs('/proc/self/cgroup')
.resolves(null)
.withArgs('/proc/self/mountinfo')
.resolves(null);
FsMock.promises.readFile
.withArgs('/proc/self/cgroup', 'utf-8')
.resolves('0::/')
Expand All @@ -143,31 +150,53 @@ describe('system.getGladysContainerId', () => {
expect(containerId2).to.eq('83fa542c0b140e45e63ad7263c539ac08e2cbf7916894f1c51c3f016397b168e');
});
it('should return containerId through exec in cgroup v2 (Debian 11)', async () => {
FsMock.promises.access = fake.rejects();
FsMock.promises.access
.withArgs('/var/lib/gladysassistant/containerId')
.rejects()
.withArgs('/proc/self/cgroup')
.resolves(null);
FsMock.promises.readFile = fake.resolves(procSelfCpuGroupDebia11);
const containerId2 = await system.getGladysContainerId();
expect(containerId2).to.eq('2bb2c94b0c395fc8fdff9fa4ce364a3be0dd05792145ffc93ce8d665d06521f1');
});
it('should return containerId through exec in cgroup v2 (Debian 11) with containerId not on first line', async () => {
FsMock.promises.access = fake.rejects();
FsMock.promises.access
.withArgs('/var/lib/gladysassistant/containerId')
.rejects()
.withArgs('/proc/self/cgroup')
.resolves(null);
FsMock.promises.readFile = fake.resolves(procSelfCpuGroupDebia11WithDataInSecondLine);
const containerId2 = await system.getGladysContainerId();
expect(containerId2).to.eq('2bb2c94b0c395fc8fdff9fa4ce364a3be0dd05792145ffc93ce8d665d06521f1');
});
it('should return containerId through exec in cgroup v1 (Debian 10)', async () => {
FsMock.promises.access = fake.rejects();
FsMock.promises.access
.withArgs('/var/lib/gladysassistant/containerId')
.rejects()
.withArgs('/proc/self/cgroup')
.resolves(null);
FsMock.promises.readFile = fake.resolves(procSelfCpuGroupDebian10);
const containerId2 = await system.getGladysContainerId();
expect(containerId2).to.eq('357e73ad015211a5acd76a8973b9287d4de75922e9802d94ba46b756f2bb5350');
});
it('should return containerId through exec in cgroup v1 (Debian 10) with containerId not on first line', async () => {
FsMock.promises.access = fake.rejects();
FsMock.promises.access
.withArgs('/var/lib/gladysassistant/containerId')
.rejects()
.withArgs('/proc/self/cgroup')
.resolves(null);
FsMock.promises.readFile = fake.resolves(procSelfCpuGroupDebian10WithDataInSecondLine);
const containerId2 = await system.getGladysContainerId();
expect(containerId2).to.eq('357e73ad015211a5acd76a8973b9287d4de75922e9802d94ba46b756f2bb5350');
});
it('should return error, system not compatible', async () => {
FsMock.promises.access = fake.rejects();
FsMock.promises.access
.withArgs('/var/lib/gladysassistant/containerId')
.rejects()
.withArgs('/proc/self/mountinfo')
.rejects()
.withArgs('/proc/self/cgroup')
.resolves(null);
FsMock.promises.readFile = fake.resolves('3:rdma:/');
try {
await system.getGladysContainerId();
Expand Down

0 comments on commit 1a68f49

Please sign in to comment.