diff --git a/README.md b/README.md index c2b0969..9818944 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,12 @@ const executor = new DockerExecutor({ For more information on `start`, `stop`, and `stats` please see the [executor-base]. +### Job annotations + +| Annotation | Type | Description | +| :--------- | :--- | :----------- | +| `screwdriver.cd/dockerEnabled` | Boolean | Opts the build container into `Privileged` mode with the host's Docker socket (`/var/run/docker.sock`) bind-mounted in. Off by default — only enable this for jobs that specifically need to build or run Docker containers, since it grants the build full host-level access. | + ## Testing ```bash diff --git a/index.js b/index.js index e003f3d..6d49ba1 100644 --- a/index.js +++ b/index.js @@ -132,6 +132,9 @@ class DockerExecutor extends Executor { * @param {Integer} config.buildId ID for the build * @param {String} config.container Container for the build to run in * @param {String} config.token JWT for the Build + * @param {Object} [config.annotations] Job annotations. `screwdriver.cd/dockerEnabled` opts + * the build container into `Privileged` mode with the host's + * Docker socket mounted in; both are off by default. * @return {Promise} */ @@ -141,6 +144,8 @@ class DockerExecutor extends Executor { let buildImage = piecesParts.name; const buildTimeout = hoek.reach(config, 'annotations>screwdriver.cd/timeout', { separator: '>' }); const timeout = parseInt(buildTimeout || DEFAULT_BUILD_TIMEOUT, 10); + const dockerEnabled = + hoek.reach(config, 'annotations>screwdriver.cd/dockerEnabled', { separator: '>' }) === true; /** * @@ -209,8 +214,8 @@ class DockerExecutor extends Executor { // 3 GB of memory + swap (aka, 1 GB of swap) MemoryLimit: 3 * 1024 * 1024 * 1024, VolumesFrom: [`${launchContainer.id}:rw`], - Privileged: true, - Binds: ['/var/run/docker.sock:/var/run/docker.sock'] + Privileged: dockerEnabled, + Binds: dockerEnabled ? ['/var/run/docker.sock:/var/run/docker.sock'] : [] } }) ) diff --git a/test/index.test.js b/test/index.test.js index 292db93..8d07fd6 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -145,8 +145,8 @@ describe('index', function () { Memory: 2 * 1024 * 1024 * 1024, MemoryLimit: 3 * 1024 * 1024 * 1024, VolumesFrom: ['launcherID:rw'], - Privileged: true, - Binds: ['/var/run/docker.sock:/var/run/docker.sock'] + Privileged: false, + Binds: [] } }; }); @@ -212,6 +212,73 @@ describe('index', function () { }); }); + it('defaults to Privileged: false and no docker socket bind', () => { + dockerMock.createContainer.yieldsAsync(new Error('bad container args')); + dockerMock.createContainer.withArgs(launcherArgs).yieldsAsync(null, launcherContainer); + dockerMock.createContainer.withArgs(buildArgs).yieldsAsync(null, buildContainer); + + return executor + .start({ + buildId, + container, + apiUri, + token + }) + .then(() => { + const containerArgs = dockerMock.createContainer.secondCall.args[0]; + + assert.isFalse(containerArgs.HostConfig.Privileged); + assert.deepEqual(containerArgs.HostConfig.Binds, []); + }); + }); + + it('enables Privileged mode and the docker socket bind when screwdriver.cd/dockerEnabled is set', () => { + buildArgs.HostConfig.Privileged = true; + buildArgs.HostConfig.Binds = ['/var/run/docker.sock:/var/run/docker.sock']; + + dockerMock.createContainer.yieldsAsync(new Error('bad container args')); + dockerMock.createContainer.withArgs(launcherArgs).yieldsAsync(null, launcherContainer); + dockerMock.createContainer.withArgs(buildArgs).yieldsAsync(null, buildContainer); + + return executor + .start({ + buildId, + container, + apiUri, + token, + annotations: { + 'screwdriver.cd/dockerEnabled': true + } + }) + .then(() => { + assert.calledWith(dockerMock.createContainer, buildArgs); + assert.callCount(buildContainer.start, 1); + }); + }); + + it('keeps Privileged: false and no docker socket bind when screwdriver.cd/dockerEnabled is the string "false"', () => { + dockerMock.createContainer.yieldsAsync(new Error('bad container args')); + dockerMock.createContainer.withArgs(launcherArgs).yieldsAsync(null, launcherContainer); + dockerMock.createContainer.withArgs(buildArgs).yieldsAsync(null, buildContainer); + + return executor + .start({ + buildId, + container, + apiUri, + token, + annotations: { + 'screwdriver.cd/dockerEnabled': 'false' + } + }) + .then(() => { + const containerArgs = dockerMock.createContainer.secondCall.args[0]; + + assert.isFalse(containerArgs.HostConfig.Privileged); + assert.deepEqual(containerArgs.HostConfig.Binds, []); + }); + }); + it('supports prefixed containers', () => { const prefix = 'beta_'; const buildImageArgs = { @@ -239,8 +306,8 @@ describe('index', function () { Memory: 2 * 1024 * 1024 * 1024, MemoryLimit: 3 * 1024 * 1024 * 1024, VolumesFrom: ['launcherID:rw'], - Privileged: true, - Binds: ['/var/run/docker.sock:/var/run/docker.sock'] + Privileged: false, + Binds: [] } };