Page MenuHomePhabricator

Docker-based npm jobs have unwritable homedir
Closed, ResolvedPublic

Description

One of the most popular tools for tracking code coverage in JavaScript is Istanbul (and its command-line runner: nyc).

Unfortunately, it seems using this on Wikimedia CI leads to a cryptic error.

+ npm run-script test

> nyc -r text -r html qunit test/

/src/node_modules/nyc/node_modules/mkdirp/index.js:90
                    throw err0;
                    ^

Error: EACCES: permission denied, mkdir '/nonexistent'
    at Error (native)
    at Object.fs.mkdirSync (fs.js:923:18)
    at sync (/src/node_modules/nyc/node_modules/mkdirp/index.js:71:13)
    at Function.sync (/src/node_modules/nyc/node_modules/mkdirp/index.js:77:24)
    at setup (/src/node_modules/nyc/node_modules/spawn-wrap/index.js:414:10)
    at wrap (/src/node_modules/nyc/node_modules/spawn-wrap/index.js:60:18)
    at Object.<anonymous> (/src/node_modules/nyc/bin/nyc.js:57:3)

(Filed upstream at https://github.com/istanbuljs/nyc/issues/951).

It turns out, one of Instanbul's indirect dependencies needs to store a the process ID for something, and does so in a temporary file under the home directory. It would then clean this up afterward.

Arguably such values should be stored in a tmpdir. But, that's an upstream issue. I was able to workaround this problem by finding an undocumented injection path for the PID file, but that won't work for everyone.

Allowing jobs to write to their home directory would make us compatible with a larger eco system of tools in the world, as well for interoperability with other continuous integration environments (Travis CI, Jenkins, AppVeyor, GitLab, etc.).

"Home directory" here is defined as the directory referenced by the HOME environment variable, and is expected to be equally ephemeral as TMPDIR and WORKSPACE, etc.

Event Timeline

We went running the containerized process as user nobody which indeed has its home directory set to a non existent directory: /nonexistant. That caused a few issues here and there when software just hardcode cache/data paths to the home dir instead of respecting the XDG directories (see XDG directories spec). I have refrained to create a dummy home dir, that helps catches softwares that fails to write to XDG_CACHE_HOME=/cache.

https://github.com/tapjs/spawn-wrap#environment-variables has:

ENVIRONMENT VARIABLES

Spawn-wrap responds to two environment variables, both of which are preserved through child processes.

SPAWN_WRAP_DEBUG=1 in the environment will make this module dump a lot of information to stderr.

SPAWN_WRAP_SHIM_ROOT can be set to a path on the filesystem where the shim files are written in a .node-spawn-wrap-<id> folder. By default this is done in $HOME, but in some environments you may wish to point it at some other root. (For example, if $HOME is mounted as read-only in a virtual machine or container.)

That is available since v1.4.0 ( https://github.com/tapjs/spawn-wrap/commit/e5dd4a2c0a00e901ef8f907ed13d1df04f9cb41c ).

Instead of $HOME it should use one of:

  • $XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored. If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share should be used.
  • $XDG_CACHE_HOME defines the base directory relative to which user specific non-essential data files should be stored. If $XDG_CACHE_HOME is either not set or empty, a default equal to $HOME/.cache should be used.
  • $XDG_RUNTIME_DIR defines the base directory relative to which user-specific non-essential runtime files and other file objects (such as sockets, named pipes, ...) should be stored. The directory MUST be owned by the user, and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700.

Meanwhile I guess we can set SPAWN_WRAP_SHIM_ROOT=/tmp in the containers?

Running into the same problem at https://gerrit.wikimedia.org/r/#/c/mediawiki/extensions/examples/+/482488/.

Meanwhile I guess we can set SPAWN_WRAP_SHIM_ROOT in the containers?

Sounds good to me. I've submitted a patch for review that does that.

Change 482527 had a related patch set uploaded (by Krinkle; owner: Krinkle):
[integration/config@master] Fix nyc and npm-update bugs due to unwritable HOME

https://gerrit.wikimedia.org/r/482527

Change 482527 merged by jenkins-bot:
[integration/config@master] Fix nyc and npm-update bugs due to unwritable HOME

https://gerrit.wikimedia.org/r/482527

Krinkle triaged this task as Medium priority.
Krinkle edited projects, added Performance-Team; removed Performance-Team (Radar).

Change 485336 had a related patch set uploaded (by Krinkle; owner: Krinkle):
[integration/config@master] Update node10 jobs to latest dockerfile version

https://gerrit.wikimedia.org/r/485336

Change 485337 had a related patch set uploaded (by Krinkle; owner: Krinkle):
[performance/fresnel@master] build: Remove spawn-wrap bug workaround

https://gerrit.wikimedia.org/r/485337

Change 485336 merged by jenkins-bot:
[integration/config@master] Update node10 jobs to latest dockerfile version

https://gerrit.wikimedia.org/r/485336

Change 485351 had a related patch set uploaded (by Krinkle; owner: Krinkle):
[integration/config@master] Update npm-node-6-docker jobs to newer docker image

https://gerrit.wikimedia.org/r/485351

Change 485351 merged by jenkins-bot:
[integration/config@master] Update npm-node-6-docker jobs to newer docker image

https://gerrit.wikimedia.org/r/485351

Change 485337 merged by jenkins-bot:
[performance/fresnel@master] build: Remove spawn-wrap bug workaround

https://gerrit.wikimedia.org/r/485337