UNPKG

10.9 kBJavaScriptView Raw
1'use strict';
2var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 return new (P || (P = Promise))(function (resolve, reject) {
4 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6 function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
7 step((generator = generator.apply(thisArg, _arguments || [])).next());
8 });
9};
10const { generateDockerDebugOpts } = require('./debug');
11const debug = require('debug')('docker-opts');
12const nestedObjectAssign = require('nested-object-assign');
13const { addEnv } = require('./install/env');
14const definition = require('./definition');
15const _ = require('lodash');
16const { red } = require('colors');
17const httpx = require('httpx');
18const getVisitor = require('../lib/visitor').getVisitor;
19const pkg = require('../package.json');
20const NAS_UID = 10003;
21const NAS_GID = 10003;
22const DEFAULT_REGISTRY = pkg['fc-docker'].registry_default || 'registry.hub.docker.com';
23const DOCKER_REGISTRIES = pkg['fc-docker'].registry_mirrors || ['registry.hub.docker.com'];
24let DOCKER_REGISTRY_CACHE;
25const runtimeImageMap = {
26 'nodejs6': 'nodejs6',
27 'nodejs8': 'nodejs8',
28 'nodejs10': 'nodejs10',
29 'nodejs12': 'nodejs12',
30 'python2.7': 'python2.7',
31 'python3': 'python3.6',
32 'java8': 'java8',
33 'php7.2': 'php7.2',
34 'dotnetcore2.1': 'dotnetcore2.1',
35 'custom': 'custom'
36};
37function resolveDockerEnv(envs = {}) {
38 return _.map(addEnv(envs || {}), (v, k) => `${k}=${v}`);
39}
40function doImageRegisterEventTag(el) {
41 return __awaiter(this, void 0, void 0, function* () {
42 const visitor = yield getVisitor();
43 visitor.event({
44 ec: 'imageRegistry',
45 ea: 'resolve',
46 el
47 }).send();
48 });
49}
50function resolveDockerRegistry() {
51 return __awaiter(this, void 0, void 0, function* () {
52 yield doImageRegisterEventTag('start');
53 if (DOCKER_REGISTRY_CACHE) {
54 return DOCKER_REGISTRY_CACHE;
55 }
56 const promises = DOCKER_REGISTRIES.map(r => httpx.request(`https://${r}/v2/aliyunfc/runtime-nodejs8/tags/list`, { timeout: 3000 }).then(() => r));
57 try {
58 DOCKER_REGISTRY_CACHE = yield Promise.race(promises);
59 }
60 catch (error) {
61 DOCKER_REGISTRY_CACHE = DEFAULT_REGISTRY;
62 }
63 yield doImageRegisterEventTag(DOCKER_REGISTRY_CACHE);
64 return DOCKER_REGISTRY_CACHE;
65 });
66}
67const IMAGE_VERSION = pkg['fc-docker'].version || '1.9.2';
68function resolveRuntimeToDockerImage(runtime, isBuild) {
69 return __awaiter(this, void 0, void 0, function* () {
70 if (runtimeImageMap[runtime]) {
71 const name = runtimeImageMap[runtime];
72 var imageName;
73 if (isBuild) {
74 imageName = `aliyunfc/runtime-${name}:build-${IMAGE_VERSION}`;
75 }
76 else {
77 imageName = `aliyunfc/runtime-${name}:${IMAGE_VERSION}`;
78 }
79 debug('imageName: ' + imageName);
80 return imageName;
81 }
82 throw new Error(red(`invalid runtime name ${runtime}`));
83 });
84}
85function resolveImageNameForPull(imageName) {
86 return __awaiter(this, void 0, void 0, function* () {
87 const dockerImageRegistry = yield resolveDockerRegistry();
88 if (dockerImageRegistry) {
89 imageName = `${dockerImageRegistry}/${imageName}`;
90 }
91 return imageName;
92 });
93}
94function generateInstallOpts(imageName, mounts, envs) {
95 return {
96 Image: imageName,
97 Tty: true,
98 Env: resolveDockerEnv(envs),
99 Cmd: ['/bin/bash'],
100 HostConfig: {
101 AutoRemove: true,
102 Mounts: mounts
103 }
104 };
105}
106function generateContainerName(serviceName, functionName, debugPort) {
107 return `fun-local-${serviceName}-${functionName}`.replace(/ /g, '')
108 + (debugPort ? '-debug' : '-run');
109}
110function generateContainerNameFilter(containerName, inited) {
111 if (inited) {
112 return `{"name": ["${containerName}-inited"]}`;
113 }
114 return `{"name": ["${containerName}"]}`;
115}
116function generateSboxOpts({ imageName, hostname, mounts, envs, cmd = [], isTty, isInteractive }) {
117 return {
118 Image: imageName,
119 Hostname: hostname,
120 AttachStdin: isInteractive,
121 AttachStdout: true,
122 AttachStderr: true,
123 User: resolveDockerUser({ stage: 'sbox' }),
124 Tty: isTty,
125 OpenStdin: isInteractive,
126 StdinOnce: true,
127 Env: resolveDockerEnv(envs),
128 Cmd: cmd.length ? cmd : ['/bin/bash'],
129 HostConfig: {
130 AutoRemove: true,
131 Mounts: mounts
132 }
133 };
134}
135function transformPathForVirtualBox(source) {
136 // C:\\Users\\image_crawler\\code -> /c/Users/image_crawler/code
137 const sourcePath = source.split(':').join('');
138 const lowerFirstAndReplace = _.lowerFirst(sourcePath.split('\\').join('/'));
139 return '/' + lowerFirstAndReplace;
140}
141function transformMountsForToolbox(mounts) {
142 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`));
143 if (Array.isArray(mounts)) {
144 return mounts.map(m => {
145 return transformSourcePathOfMount(m);
146 });
147 }
148 return transformSourcePathOfMount(mounts);
149}
150function transformSourcePathOfMount(mountsObj) {
151 if (!_.isEmpty(mountsObj)) {
152 const replaceMounts = Object.assign({}, mountsObj);
153 replaceMounts.Source = transformPathForVirtualBox(mountsObj.Source);
154 return replaceMounts;
155 }
156 return {};
157}
158function generateContainerBuildOpts(runtime, containerName, mounts, cmd, envs, preferredImage) {
159 return __awaiter(this, void 0, void 0, function* () {
160 const hostOpts = {
161 HostConfig: {
162 AutoRemove: true,
163 Mounts: mounts
164 }
165 };
166 const ioOpts = {
167 OpenStdin: true,
168 Tty: false,
169 StdinOnce: true,
170 AttachStdin: true,
171 AttachStdout: true,
172 AttachStderr: true
173 };
174 const imageName = yield resolveRuntimeToDockerImage(runtime, true);
175 const opts = nestedObjectAssign({
176 Env: resolveDockerEnv(envs),
177 Image: preferredImage || imageName,
178 name: containerName,
179 Cmd: cmd,
180 User: resolveDockerUser({ stage: 'build' })
181 }, ioOpts, hostOpts);
182 debug('fc-docker docker options: %j', opts);
183 return opts;
184 });
185}
186function generateLocalInvokeOpts(runtime, containerName, mounts, cmd, debugPort, envs, dockerUser, debugIde) {
187 return __awaiter(this, void 0, void 0, function* () {
188 const hostOpts = {
189 HostConfig: {
190 AutoRemove: true,
191 Mounts: mounts
192 }
193 };
194 let debugOpts = {};
195 if (debugPort) {
196 debugOpts = generateDockerDebugOpts(runtime, debugPort, debugIde);
197 }
198 const ioOpts = {
199 OpenStdin: true,
200 Tty: false,
201 StdinOnce: true,
202 AttachStdin: true,
203 AttachStdout: true,
204 AttachStderr: true
205 };
206 const imageName = yield resolveRuntimeToDockerImage(runtime);
207 supportCustomBootstrapFile(runtime, envs);
208 const opts = nestedObjectAssign({
209 Env: resolveDockerEnv(envs),
210 Image: imageName,
211 name: containerName,
212 Cmd: cmd,
213 User: dockerUser
214 }, ioOpts, hostOpts, debugOpts);
215 debug('fc-docker docker options: %j', opts);
216 return opts;
217 });
218}
219function resolveMockScript(runtime) {
220 return `/var/fc/runtime/${runtime}/mock`;
221}
222/**
223 * 支持通过 BOOTSTRAP_FILE 环境变量改变 bootstrap 文件名。
224**/
225function supportCustomBootstrapFile(runtime, envs) {
226 if (runtime === 'custom') {
227 if (envs['BOOTSTRAP_FILE']) {
228 envs['AGENT_SCRIPT'] = envs['BOOTSTRAP_FILE'];
229 }
230 }
231}
232function generateLocalStartOpts(runtime, name, mounts, cmd, debugPort, envs, dockerUser, debugIde) {
233 return __awaiter(this, void 0, void 0, function* () {
234 const hostOpts = {
235 HostConfig: {
236 AutoRemove: true,
237 Mounts: mounts
238 }
239 };
240 let debugOpts = {};
241 if (debugPort) {
242 debugOpts = generateDockerDebugOpts(runtime, debugPort, debugIde);
243 }
244 const imageName = yield resolveRuntimeToDockerImage(runtime);
245 supportCustomBootstrapFile(runtime, envs);
246 const opts = nestedObjectAssign({
247 Env: resolveDockerEnv(envs),
248 Image: imageName,
249 name,
250 Cmd: cmd,
251 User: dockerUser,
252 Entrypoint: [resolveMockScript(runtime)]
253 }, hostOpts, debugOpts);
254 debug('docker options: %j', opts);
255 return opts;
256 });
257}
258// Not Run stage:
259// for linux platform, it will always use process.uid and process.gid
260// for mac and windows platform, it will always use 0
261// Run stage:
262// for linux platform, it will always use process.uid and process.gid
263// for mac and windows platform, it will use 10003 if no nasConfig, otherwise it will use nasConfig userId
264function resolveDockerUser({ nasConfig, stage = 'run' }) {
265 let { userId, groupId } = definition.getUserIdAndGroupId(nasConfig);
266 if (process.platform === 'linux') {
267 debug('For linux platform, Fun will use host userId and groupId to build or run your functions');
268 userId = process.getuid();
269 groupId = process.getgid();
270 }
271 else {
272 if (stage === 'run') {
273 if (userId === -1 || userId === undefined) {
274 userId = NAS_UID;
275 }
276 if (groupId === -1 || groupId === undefined) {
277 groupId = NAS_GID;
278 }
279 }
280 else {
281 userId = 0;
282 groupId = 0;
283 }
284 }
285 return `${userId}:${groupId}`;
286}
287module.exports = {
288 generateLocalInvokeOpts, resolveRuntimeToDockerImage,
289 generateInstallOpts, generateSboxOpts,
290 generateLocalStartOpts,
291 resolveMockScript, resolveDockerEnv, transformPathForVirtualBox,
292 resolveDockerRegistry, transformMountsForToolbox, transformSourcePathOfMount,
293 DOCKER_REGISTRIES, generateContainerBuildOpts,
294 IMAGE_VERSION, resolveImageNameForPull, generateContainerName,
295 generateContainerNameFilter, resolveDockerUser
296};