Skip to content

Commit

Permalink
fix_mounting_when_fun_install_on_docker_toolbox (#277)
Browse files Browse the repository at this point in the history
  • Loading branch information
coco-super authored and tanhe123 committed Aug 6, 2019
1 parent 0511b28 commit 9fd1cbb
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 30 deletions.
16 changes: 16 additions & 0 deletions docs/usage/faq-zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,20 @@ Resources:

![](https://tan-blog.oss-cn-hangzhou.aliyuncs.com/img/20181214112400.png)

### Fun local invoke && Fun local start

本地使用 Fun 时,如果需要在本地运行、调试函数,则需要使用 fun local 子命令。使用 fun local 子命令就需要预先安装 Docker。

如果在您的 Windows 系统上安装的是 Docker Toolbox,在本地使用 `fun local invoke` 或者 `fun local start` 命令时提示信息如下:<br />![image.png](/figures/fun_local_error_on_toolbox.png)

提示默认主机路径为 C:\Users,Docker Toolbox 只能挂载 C 盘当前用户的目录,挂载其它盘都不会生效。错误信息中路径为 `D:\image_crawler`,所以失败。<br />如果想挂载其它盘符的路径,步骤如下:<br />1.打开 `Oracle VM VirtualBox`

![image.png](/figures/virtual-box.png)

2.选择共享文件夹,选择添加,选择我们需要共享的文件夹。确定并重启 Virtual Box。

![image.png](/figures/steps.png)

****: step 5 中的**共享文件夹名称**应按照上述格式手动填写。盘符小写,且以 `/` 为分隔符,同时保证路径完整性。例如:`d/fun/demo``e/fun/work` ...

由于 `Docker Toolbox` 官方也已经不在维护,为了更好的体验,我们希望您使用 [Docker For Windows](http://mirrors.aliyun.com/docker-toolbox/windows/docker-for-windows/beta/)。(建议使用我们提供的安装链接,某些版本的 Docker for Windows 可能存在不稳定的问题。)
Binary file added figures/fun_local_error_on_toolbox.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added figures/steps.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added figures/virtual-box.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 21 additions & 19 deletions lib/docker-opts.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ async function resolveRuntimeToDockerImage(runtime, isBuild) {
throw new Error(red(`invalid runtime name ${runtime}`));
}


function generateInstallOpts(imageName, mounts, envs) {
return {
Image: imageName,
Expand All @@ -96,36 +97,39 @@ function generateInstallOpts(imageName, mounts, envs) {
};
}

async function pathTransformationToVirtualBox(source) {
function transformPathForVirtualBox(source) {
// C:\\Users\\image_crawler\\code -> /c/Users/image_crawler/code
const souecePath = source.split(':').join('');
const lowerFirstAndReplace = _.lowerFirst(souecePath.split(path.sep).join('/'));
const sourcePath = source.split(':').join('');
const lowerFirstAndReplace = _.lowerFirst(sourcePath.split(path.sep).join('/'));
return '/' + lowerFirstAndReplace;
}

async function detectedToolBoxAndPathTransformation(mounts) {

const isDockerToolBox = await require('./docker.js').isDockerToolBox();
function transformMountsForToolbox(mounts) {

if (isDockerToolBox) {
console.warn(red(`We detected that you are using docker toolbox. For a better experience, please upgrade 'docker for windows'.\nYou can refer to Chinese doc https://github.com/alibaba/funcraft/blob/master/docs/usage/installation-zh.md#windows-%E5%AE%89%E8%A3%85-docker or English doc https://github.com/alibaba/funcraft/blob/master/docs/usage/installation.md.\n`));

console.warn(red(`We detected that you are using docker toolbox. For a better experience, please upgrade 'docker for windows'.\nYou can refer to Chinese doc https://github.com/alibaba/funcraft/blob/master/docs/usage/installation-zh.md#windows-%E5%AE%89%E8%A3%85-docker or English doc https://github.com/alibaba/funcraft/blob/master/docs/usage/installation.md.\n`));
if (Array.isArray(mounts)) {
return mounts.map(m => {

mounts.forEach(async element => {
return transformSourcePathOfMount(m);
});
}
return transformSourcePathOfMount(mounts);
}

if (Reflect.ownKeys(element).length > 0 && element.Source.indexOf('C:\\Users') !== -1) {
function transformSourcePathOfMount(mountsObj) {

element.Source = await pathTransformationToVirtualBox(element.Source);
if (!_.isEmpty(mountsObj)) {

}
});
const replaceMounts = Object.assign({}, mountsObj);
replaceMounts.Source = transformPathForVirtualBox(mountsObj.Source);
return replaceMounts;
}
return {};
}

async function generateLocalInvokeOpts(runtime, containerName, mounts, cmd, debugPort, envs, dockerUser) {

await detectedToolBoxAndPathTransformation(mounts);

const hostOpts = {
HostConfig: {
AutoRemove: true,
Expand Down Expand Up @@ -174,8 +178,6 @@ function resolveMockScript(runtime) {

async function generateLocalStartRunOpts(runtime, name, mounts, cmd, debugPort, envs, dockerUser) {

await detectedToolBoxAndPathTransformation(mounts);

const hostOpts = {
HostConfig: {
AutoRemove: true,
Expand Down Expand Up @@ -211,6 +213,6 @@ async function generateLocalStartRunOpts(runtime, name, mounts, cmd, debugPort,
module.exports = {
generateLocalInvokeOpts, resolveRuntimeToDockerImage,
generateInstallOpts, generateLocalStartRunOpts,
resolveMockScript, resolveDockerEnv, pathTransformationToVirtualBox,
resolveDockerImageRepo
resolveMockScript, resolveDockerEnv, transformPathForVirtualBox,
resolveDockerImageRepo, transformMountsForToolbox, transformSourcePathOfMount
};
10 changes: 7 additions & 3 deletions lib/docker.js
Original file line number Diff line number Diff line change
Expand Up @@ -436,10 +436,9 @@ async function createContainer(opts) {
container = await docker.createContainer(opts);
} catch (ex) {

if (ex.message.indexOf('mount path must be absolute') !== -1) {
if (ex.message.indexOf('invalid mount config for type') !== -1 && await isDockerToolBox()) {

throw new Error(red(`The default host machine path for docker toolbox is under 'C:\\Users', Please make sure your project is in this directory.`));

throw new Error(red(`The default host machine path for docker toolbox is under 'C:\\Users', Please make sure your project is in this directory. If you want to mount other disk paths, please refer to https://github.com/alibaba/funcraft/blob/master/docs/usage/faq-zh.md .`));
}
throw ex;
}
Expand Down Expand Up @@ -556,6 +555,11 @@ async function startInstallationContainer({ runtime, imageName, codeUri, targets
debug(`runtime: ${runtime}`);
debug(`codeUri: ${codeUri}`);

if (await isDockerToolBox()) {

throw new Error(red(`\nWe detected that you are using docker toolbox. For a better experience, please upgrade 'docker for windows'.\nYou can refer to Chinese doc https://github.com/alibaba/funcraft/blob/master/docs/usage/installation-zh.md#windows-%E5%AE%89%E8%A3%85-docker or English doc https://github.com/alibaba/funcraft/blob/master/docs/usage/installation.md.`));
}

if (!imageName) {
imageName = await dockerOpts.resolveRuntimeToDockerImage(runtime, true);
if (!imageName) {
Expand Down
12 changes: 11 additions & 1 deletion lib/local/invoke.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,17 @@ class Invoke {
this.nasMounts = await docker.resolveNasConfigToMounts(this.serviceName, this.nasConfig, this.tplPath);
this.codeMount = await docker.resolveCodeUriToMount(this.codeUri);

this.mounts = [this.codeMount, ...this.nasMounts];
const allMount = [this.codeMount, ...this.nasMounts];

const isDockerToolBox = await docker.isDockerToolBox();

if (isDockerToolBox) {

this.mounts = dockerOpts.transformMountsForToolbox(allMount);
} else {

this.mounts = allMount;
}

debug(`docker mounts: %s`, JSON.stringify(this.mounts, null, 4));

Expand Down
25 changes: 18 additions & 7 deletions test/docker-opts.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ const { setProcess } = require('./test-utils');
const os = require('os');
const DockerCli = require('dockerode');
const sinon = require('sinon');
const assert = sinon.assert;
const sandbox = sinon.createSandbox();
const proxyquire = require('proxyquire');

Expand Down Expand Up @@ -132,8 +131,6 @@ describe('test generateLocalInvokeOpts', () => {
ReadOnly: true
}], 'cmd', 9000, envs, '1000:1000');

assert.calledOnce(DockerCli.prototype.info);

expect(opts).to.eql({
'name': 'test',
'Cmd': 'cmd',
Expand Down Expand Up @@ -187,8 +184,6 @@ describe('test generateLocalInvokeOpts', () => {
ReadOnly: true
}], null, null, null, null);

assert.calledOnce(DockerCli.prototype.info);

expect(opts).to.eql({
'name': 'test',
'Cmd': null,
Expand Down Expand Up @@ -260,12 +255,28 @@ describe('test resolveDockerEnv', () => {
});
});

describe('test pathTransformationToVirtualBox', () => {
describe('test transformPathForVirtualBox', () => {
it('test default host machine path', async () => {
if (process.platform === 'win32') {
const source = 'C:\\Users\\WB-SFY~1\\AppData\\Local\\Temp';
const result = await dockerOpts.pathTransformationToVirtualBox(source);
const result = await dockerOpts.transformPathForVirtualBox(source);
expect(result).to.eql('/c/Users/WB-SFY~1/AppData/Local/Temp');
}
});

it('test transformSourcePathOfMount', async () => {
const result = await dockerOpts.transformSourcePathOfMount({
'Type': 'bind',
'Source': 'C:\\Users\\image_crawler\\code',
'Target': '/code',
'ReadOnly': true
});

expect(result).to.eql({
'Type': 'bind',
'Source': '/c/Users/image_crawler/code',
'Target': '/code',
'ReadOnly': true
});
});
});
21 changes: 21 additions & 0 deletions test/docker.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -493,4 +493,25 @@ describe('test conventInstallTargetsToMounts', () => {
}
]);
});
});


describe('test isDockerToolBox', () => {

var isWin = process.platform === 'win32';

beforeEach(() => {

sandbox.stub(DockerCli.prototype, 'info').resolves({'Labels': ['provider=virtualbox']});
});

afterEach(() => {
sandbox.restore();
});

(isWin ? it : it.skip)('test isDockerToolBox', async () => {

const result = await docker.isDockerToolBox();
expect(result).to.be(true);
});
});

0 comments on commit 9fd1cbb

Please sign in to comment.