UNPKG

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