Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature(@embark/core): IPC adapts when run in Docker Linux on Win #1202

Closed
wants to merge 1 commit into from

Conversation

michaelsbradleyjr
Copy link
Contributor

When embark is running on Linux and macOS, unix socket files are used for geth's and embark's IPC files. If the context is a Linux container running on a Windows Docker host, and if the DApp is mounted from the host's file system, there is a problem: unix socket files are incompatible with the Windows file system.

Detect the problematic scenario and use a path outside of the mounted directory for embark's and geth's IPC files.

To avoid a circular dependency problem, remove the utils/utils.js dependency from core/env.js, don't have utils/host.ts depdend on core/fs.js, and implement the ipcPath() helper as a static method on the class exported from core/ipc.js.

@michaelsbradleyjr michaelsbradleyjr requested a review from a team December 18, 2018 04:02
Copy link
Contributor

@0x-r4bbit 0x-r4bbit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codewise this looks pretty solid!

Left some minor comments.

@@ -2,7 +2,7 @@

const {execSync} = require('child_process');
const {delimiter} = require('path');
const {joinPath} = require('../utils/utils.js');
const {join} = require('path');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 great move!

Also, can we combine the required symbols for path? There's another one already for delimiter.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, will combine them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

).test(
execSync(
"cat /proc/self/cgroup",
{stdio: ["ignore", "pipe", "ignore"]},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@michaelsbradleyjr just out of curiosity: why are we doing ignore, pipe, ignore here and not just pipe?

Copy link
Contributor Author

@michaelsbradleyjr michaelsbradleyjr Dec 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the execSync calls in this module, all we care about is stdout, so it seems more correct to 'ignore' stdin and stderr. It would, though, work with the default: 'pipe', which is equivalent to ['pipe', 'pipe', 'pipe'].

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, that makes sense!

.toString()
.split("\n")
.filter((line) => /nounix/.test(line))
.some((line) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some cosmetics that can be ignored: we can get rid of the parenthesis here in filter() and some

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't have them originally but tslint said it was an error to not use parens around line.

Copy link
Contributor Author

@michaelsbradleyjr michaelsbradleyjr Dec 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When removed, I get something like this:

$ yarn lint:ts
yarn run v1.12.3
$ tslint -c tslint.json 'src/**/*.ts'

ERROR: src/lib/utils/host.ts[42, 15]: Parentheses are required around the parameters of an arrow function definition

error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Maybe it's something we can relax in the linter, and/or we could have another team discussion about adopting use of the prettier tool?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow I'm surprised tslint is complaining about that. Definitely something we should relax in the future.

@michaelsbradleyjr michaelsbradleyjr force-pushed the refactor/ipc-location branch 4 times, most recently from f6bbbb1 to 6f219e2 Compare December 18, 2018 18:43
When embark is running on Linux and macOS, unix socket files are used for
geth's and embark's IPC files. If the context is a Linux container running on a
Windows Docker host, and if the DApp is mounted from the host's file system,
there is a problem: unix socket files are incompatible with the Windows file
system.

Detect the problematic scenario and use a path outside of the mounted directory
for embark's and geth's IPC files.

To avoid a circular dependency problem, remove the `utils/utils.js` dependency
from `core/env.js`, don't have `utils/host.ts` depdend on `core/fs.js`, and
implement the `ipcPath()` helper as a static method on the class exported from
`core/ipc.js`.
@@ -1,8 +1,7 @@
/* global __dirname module process require */

const {execSync} = require('child_process');
const {delimiter} = require('path');
const {joinPath} = require('../utils/utils.js');
const {delimiter, join} = require('path');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a big fan of extracting these off of path. delimiter and join are concepts used in a lot more ways than just path, so it'll get a bit confusing down below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the usage context (args and neighboring variables/literals always have something do to w/ paths), I thought it wasn't too confusing, but willing to reconsider.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can just do const {delimiter as pathDelimiter, join as pathJoin} = require('path'); if we want them to be more clear

return `\\\\.\\pipe\\${basename}`;
} else if (isDappMountedFromWindowsDockerHost) {
ipcDir = utils.joinPath(
os.tmpdir(), `embark-${utils.sha512(fs.dappPath()).slice(0, 8)}`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is almost exactly what I was thinking! I was thinking:

embark-<dapp_dir>-<dapp_full_path_sha512.substring(0,5)>

So, as an example:

Name Full path Path
embark_demo /Users/andremedeiros/src/_sandbox/embark_demo embark-embark_demo-f47bb
embark_demo /tmp/embark_demo embark-embark_demo-74a67
test_app /Users/andremedeiros/src/github.com/embark-framework/embark/test_apps/test_app embark-test_app-17efd

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting idea to put the original path itself into the directory name. I worry that things might get weird if spaces were in the dirname, though maybe not a problem in practice.

function sha512(arg) {
const crypto = require('crypto');
const hash = crypto.createHash('sha512');
return hash.update(arg, 'utf8').digest('hex');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, just as a precaution, you want to make sure that arg is a string, so we might want it to read

return hash.update(arg.toString(), 'utf8').digest('hex');

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://nodejs.org/dist/latest-v10.x/docs/api/crypto.html#crypto_hash_update_data_inputencoding

Maybe we should just throw if it's not a string?

> ({a: 1}).toString()
'[object Object]'
> ({a: 2}).toString()
'[object Object]'

@michaelsbradleyjr
Copy link
Contributor Author

Closing in favor of a forthcoming PR that makes saving the .ipc files within os.tmpdir() the default behavior.

michaelsbradleyjr added a commit that referenced this pull request Dec 20, 2018
This PR replaces #1202.

When embark is running on Linux and macOS, unix socket files are used for
geth's and embark's IPC files. A problem can arise if a DApp is in a deeply
nested directory structure such that the character-length of the path to a
socket file exceeds the maximum supported length. See #450.

Also, if the DApp context is a Linux container running on a Windows Docker
host, and if the DApp is mounted from the host's file system, there is a
problem: unix socket files are incompatible with the Windows file system.

Solve both problems at once by storing a DApp's `.ipc` files in a directory
within `os.tmpdir()`. Use a truncated sha512 hash of the DApp's path in the
name of the temporary directory created for that purpose so that DApps won't
collide (with an acceptably low probability of collision).

Remove the `utils/utils.js` dependency from `core/env.js` and implement the
`ipcPath()` helper as a static method on the class exported from `core/ipc.js`.
@michaelsbradleyjr
Copy link
Contributor Author

Replaced by #1214.

michaelsbradleyjr added a commit that referenced this pull request Dec 20, 2018
This PR replaces #1202.

When embark is running on Linux and macOS, unix socket files are used for
geth's and embark's IPC files. A problem can arise if a DApp is in a deeply
nested directory structure such that character-length of the path to a socket
file exceeds the maximum supported length. See #450.

Also, if the DApp context is a Linux container running on a Windows Docker
host, and if the DApp is mounted from the host's file system, there is a
problem: unix socket files are incompatible with the Windows file system.

Solve both problems at once by storing a DApp's `.ipc` files in a directory
within `os.tmpdir()`. Introduce `ipcPath()` in `core/fs.js` and use a truncated
SHA-512 hash of the DApp's path in the name of the temporary directory created
for that purpose so that DApps won't collide (with an acceptably low
probability of collision).
michaelsbradleyjr added a commit that referenced this pull request Dec 20, 2018
This PR replaces #1202.

When embark is running on Linux and macOS, unix socket files are used for
geth's and embark's IPC files. A problem can arise if a DApp is in a deeply
nested directory structure such that character-length of the path to a socket
file exceeds the maximum supported length. See #450.

Also, if the DApp context is a Linux container running on a Windows Docker
host, and if the DApp is mounted from the host's file system, there is a
problem: unix socket files are incompatible with the Windows file system.

Solve both problems at once by storing a DApp's `.ipc` files in a directory
within `os.tmpdir()`. Introduce `ipcPath()` in `core/fs.js` and use a truncated
SHA-512 hash of the DApp's path in the name of the temporary directory created
for that purpose so that DApps won't collide (with an acceptably low
probability of collision).
michaelsbradleyjr added a commit that referenced this pull request Dec 21, 2018
This PR replaces #1202.

When embark is running on Linux and macOS, unix socket files are used for
geth's and embark's IPC files. A problem can arise if a DApp is in a deeply
nested directory structure such that character-length of the path to a socket
file exceeds the maximum supported length. See #450.

Also, if the DApp context is a Linux container running on a Windows Docker
host, and if the DApp is mounted from the host's file system, there is a
problem: unix socket files are incompatible with the Windows file system.

Solve both problems at once by storing a DApp's `.ipc` files in a directory
within `os.tmpdir()`. Introduce `ipcPath()` in `core/fs.js` and use a truncated
SHA-512 hash of the DApp's path in the name of the temporary directory created
for that purpose so that DApps won't collide (with an acceptably low
probability of collision).
michaelsbradleyjr added a commit that referenced this pull request Dec 21, 2018
This PR replaces #1202.

When embark is running on Linux and macOS, unix socket files are used for
geth's and embark's IPC files. A problem can arise if a DApp is in a deeply
nested directory structure such that character-length of the path to a socket
file exceeds the maximum supported length. See #450.

Also, if the DApp context is a Linux container running on a Windows Docker
host, and if the DApp is mounted from the host's file system, there is a
problem: unix socket files are incompatible with the Windows file system.

Solve both problems at once by storing a DApp's `.ipc` files in a directory
within `os.tmpdir()`. Introduce `ipcPath()` in `core/fs.js` and use a truncated
SHA-512 hash of the DApp's path in the name of the temporary directory created
for that purpose so that DApps won't collide (with an acceptably low
probability of collision).
iurimatias pushed a commit that referenced this pull request Dec 21, 2018
This PR replaces #1202.

When embark is running on Linux and macOS, unix socket files are used for
geth's and embark's IPC files. A problem can arise if a DApp is in a deeply
nested directory structure such that character-length of the path to a socket
file exceeds the maximum supported length. See #450.

Also, if the DApp context is a Linux container running on a Windows Docker
host, and if the DApp is mounted from the host's file system, there is a
problem: unix socket files are incompatible with the Windows file system.

Solve both problems at once by storing a DApp's `.ipc` files in a directory
within `os.tmpdir()`. Introduce `ipcPath()` in `core/fs.js` and use a truncated
SHA-512 hash of the DApp's path in the name of the temporary directory created
for that purpose so that DApps won't collide (with an acceptably low
probability of collision).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants