From c55dac66ed97a2317d4c696c3b505790ec5d72fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A4=95=E0=A4=BE=E0=A4=B0=E0=A4=A4=E0=A5=8B=E0=A4=AB?= =?UTF-8?q?=E0=A5=8D=E0=A4=AB=E0=A5=87=E0=A4=B2=E0=A4=B8=E0=A5=8D=E0=A4=95?= =?UTF-8?q?=E0=A5=8D=E0=A4=B0=E0=A4=BF=E0=A4=AA=E0=A5=8D=E0=A4=9F=E2=84=A2?= Date: Fri, 17 Jan 2025 13:10:51 +0100 Subject: [PATCH] fix(core): Update isDocker check to return true on kubernetes/containerd (#12603) --- packages/core/src/InstanceSettings.ts | 29 ++++++++---- packages/core/test/InstanceSettings.test.ts | 49 ++++++++++++++++----- 2 files changed, 57 insertions(+), 21 deletions(-) diff --git a/packages/core/src/InstanceSettings.ts b/packages/core/src/InstanceSettings.ts index d06f68fc12..53d9f72d6d 100644 --- a/packages/core/src/InstanceSettings.ts +++ b/packages/core/src/InstanceSettings.ts @@ -142,19 +142,30 @@ export class InstanceSettings { } /** - * Whether this instance is running inside a Docker container. - * - * Based on: https://github.com/sindresorhus/is-docker + * Whether this instance is running inside a Docker/Podman/Kubernetes container. */ @Memoized get isDocker() { + if (existsSync('/.dockerenv') || existsSync('/run/.containerenv')) return true; try { - return ( - existsSync('/.dockerenv') || readFileSync('/proc/self/cgroup', 'utf8').includes('docker') - ); - } catch { - return false; - } + const cgroupV1 = readFileSync('/proc/self/cgroup', 'utf8'); + if ( + cgroupV1.includes('docker') || + cgroupV1.includes('kubepods') || + cgroupV1.includes('containerd') + ) + return true; + } catch {} + try { + const cgroupV2 = readFileSync('/proc/self/mountinfo', 'utf8'); + if ( + cgroupV2.includes('docker') || + cgroupV2.includes('kubelet') || + cgroupV2.includes('containerd') + ) + return true; + } catch {} + return false; } update(newSettings: WritableSettings) { diff --git a/packages/core/test/InstanceSettings.test.ts b/packages/core/test/InstanceSettings.test.ts index 1fe96d3490..203a77a94b 100644 --- a/packages/core/test/InstanceSettings.test.ts +++ b/packages/core/test/InstanceSettings.test.ts @@ -214,33 +214,58 @@ describe('InstanceSettings', () => { }); it('should return true if /.dockerenv exists', () => { - mockFs.existsSync.calledWith('/.dockerenv').mockReturnValueOnce(true); + mockFs.existsSync.mockImplementation((path) => path === '/.dockerenv'); expect(settings.isDocker).toBe(true); expect(mockFs.existsSync).toHaveBeenCalledWith('/.dockerenv'); expect(mockFs.readFileSync).not.toHaveBeenCalledWith('/proc/self/cgroup', 'utf8'); }); - it('should return true if /proc/self/cgroup contains docker', () => { - mockFs.existsSync.calledWith('/.dockerenv').mockReturnValueOnce(false); - mockFs.readFileSync - .calledWith('/proc/self/cgroup', 'utf8') - .mockReturnValueOnce('docker cgroup'); - + it('should return true if /run/.containerenv exists', () => { + mockFs.existsSync.mockImplementation((path) => path === '/run/.containerenv'); expect(settings.isDocker).toBe(true); - expect(mockFs.existsSync).toHaveBeenCalledWith('/.dockerenv'); - expect(mockFs.readFileSync).toHaveBeenCalledWith('/proc/self/cgroup', 'utf8'); + expect(mockFs.existsSync).toHaveBeenCalledWith('/run/.containerenv'); + expect(mockFs.readFileSync).not.toHaveBeenCalledWith('/proc/self/cgroup', 'utf8'); }); + test.each(['docker', 'kubepods', 'containerd'])( + 'should return true if /proc/self/cgroup contains %s', + (str) => { + mockFs.existsSync.mockReturnValueOnce(false); + mockFs.readFileSync.calledWith('/proc/self/cgroup', 'utf8').mockReturnValueOnce(str); + + expect(settings.isDocker).toBe(true); + expect(mockFs.existsSync).toHaveBeenCalledWith('/.dockerenv'); + expect(mockFs.readFileSync).toHaveBeenCalledWith('/proc/self/cgroup', 'utf8'); + }, + ); + + test.each(['docker', 'kubelet', 'containerd'])( + 'should return true if /proc/self/mountinfo contains %s', + (str) => { + mockFs.existsSync.mockReturnValueOnce(false); + mockFs.readFileSync.calledWith('/proc/self/cgroup', 'utf8').mockReturnValueOnce(''); + mockFs.readFileSync.calledWith('/proc/self/mountinfo', 'utf8').mockReturnValueOnce(str); + + expect(settings.isDocker).toBe(true); + expect(mockFs.existsSync).toHaveBeenCalledWith('/.dockerenv'); + expect(mockFs.readFileSync).toHaveBeenCalledWith('/proc/self/cgroup', 'utf8'); + expect(mockFs.readFileSync).toHaveBeenCalledWith('/proc/self/mountinfo', 'utf8'); + }, + ); + it('should return false if no docker indicators are found', () => { mockFs.existsSync.calledWith('/.dockerenv').mockReturnValueOnce(false); mockFs.readFileSync.calledWith('/proc/self/cgroup', 'utf8').mockReturnValueOnce(''); + mockFs.readFileSync.calledWith('/proc/self/mountinfo', 'utf8').mockReturnValueOnce(''); expect(settings.isDocker).toBe(false); }); - it('should return false if checking for docker throws an error', () => { - mockFs.existsSync.calledWith('/.dockerenv').mockImplementationOnce(() => { - throw new Error('Access denied'); + it('should return false if reading any of these files throws an error', () => { + mockFs.existsSync.mockReturnValue(false); + mockFs.readFileSync.mockImplementation(() => { + throw new Error('File not found'); }); + expect(settings.isDocker).toBe(false); });