Skip to content

Commit d91d422

Browse files
committed
fix: nas config and logConfig
1 parent df2d6bc commit d91d422

4 files changed

Lines changed: 182 additions & 15 deletions

File tree

__tests__/e2e/nodejs/s_oss_config_auto.yaml

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,39 @@ resources:
3838
handler: index.handler
3939
memorySize: 128
4040
timeout: 60
41-
ossMountConfig: auto|mountDir=/mnt/test-oss-bucket|bucketPath=/|rules=[{"allowedOrigin":"*","allowedMethod":["GET","POST","PUT","DELETE","HEAD"],"allowedHeader":"*","exposeHeader":"Content-Length","maxAgeSeconds":30}]
41+
ossMountConfig: auto|mountDir=/mnt/test-oss-bucket|bucketPath=/|rules=[{"allowedOrigin":"*","allowedMethod":["GET","POST","PUT","DELETE","HEAD"],"allowedHeader":"*","exposeHeader":"Content-Length","maxAgeSeconds":30}]
42+
43+
fcDemo3: # 业务名称/模块名称
44+
component: ${env('fc_component_version', path('../../../'))}
45+
actions:
46+
pre-deploy:
47+
- run: npm install
48+
path: ./test-auto-code
49+
props: # 组件的属性值
50+
region: ${vars.region}
51+
functionName: fc3-event-${env('fc_component_function_name', 'nodejs18')}-nasConfig
52+
role: acs:ram::${config('AccountID')}:role/aliyunaliyunfcdefaultrole
53+
runtime: ${env('fc_component_runtime', 'nodejs18')}
54+
code: ./test-auto-code
55+
handler: index.handler
56+
memorySize: 128
57+
timeout: 60
58+
nasConfig: auto|mountDir=/mnt/fcDir|nasDir=nasDir
59+
vpcConfig: auto
60+
61+
fcDemo4: # 业务名称/模块名称
62+
component: ${env('fc_component_version', path('../../../'))}
63+
actions:
64+
pre-deploy:
65+
- run: npm install
66+
path: ./test-auto-code
67+
props: # 组件的属性值
68+
region: ${vars.region}
69+
functionName: fc3-event-${env('fc_component_function_name', 'nodejs18')}-logConfig
70+
role: acs:ram::${config('AccountID')}:role/aliyunaliyunfcdefaultrole
71+
runtime: ${env('fc_component_runtime', 'nodejs18')}
72+
code: ./test-auto-code
73+
handler: index.handler
74+
memorySize: 128
75+
timeout: 60
76+
logConfig: auto|enableRequestMetrics=false|enableInstanceMetrics=false

src/subCommands/deploy/impl/function.ts

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import FC, { GetApiType } from '../../../resources/fc';
1818
import VPC_NAS from '../../../resources/vpc-nas';
1919
import Base from './base';
2020
import { ICredentials } from '@serverless-devs/component-interface';
21-
import { calculateCRC64, getFileSize } from '../../../utils';
21+
import { calculateCRC64, getFileSize, parseAutoConfig, checkFcDir } from '../../../utils';
2222
import OSS from '../../../resources/oss';
2323
import { setNodeModulesBinPermissions } from '../../../resources/fc/impl/utils';
2424

@@ -349,22 +349,30 @@ export default class Service extends Base {
349349
if (slsAuto) {
350350
const sls = new Sls(region, credential as ICredentials);
351351
const { project, logstore } = await sls.deploy();
352+
const logAutoConfig = parseAutoConfig(this.local.logConfig as string);
353+
const logParams = logAutoConfig?.params || {};
354+
const customFields: Record<string, any> = { ...logParams };
355+
const getConfigValue = (field: string, defaultValue: any) => {
356+
return field in customFields ? customFields[field] : defaultValue;
357+
};
352358
logger.write(
353359
yellow(`Created log resource succeeded, please replace logConfig: auto in yaml with:
354360
logConfig:
355-
enableInstanceMetrics: true
356-
enableRequestMetrics: true
357-
logBeginRule: DefaultRegex
361+
enableInstanceMetrics: ${getConfigValue('enableInstanceMetrics', true)}
362+
enableRequestMetrics: ${getConfigValue('enableRequestMetrics', true)}
363+
logBeginRule: ${getConfigValue('logBeginRule', 'DefaultRegex')}
358364
logstore: ${logstore}
359365
project: ${project}\n`),
360366
);
367+
361368
this.createResource.sls = { project, logstore };
362369
_.set(this.local, 'logConfig', {
363-
enableInstanceMetrics: true,
364-
enableRequestMetrics: true,
365-
logBeginRule: 'DefaultRegex',
370+
enableInstanceMetrics: getConfigValue('enableInstanceMetrics', true),
371+
enableRequestMetrics: getConfigValue('enableRequestMetrics', true),
372+
logBeginRule: getConfigValue('logBeginRule', 'DefaultRegex'),
366373
logstore,
367374
project,
375+
...customFields,
368376
});
369377
}
370378

@@ -443,7 +451,12 @@ vpcConfig:
443451
_.set(this.local, 'vpcConfig', vpcConfig);
444452
}
445453
if (nasAuto) {
446-
let serverAddr = `${mountTargetDomain}:/${functionName}`;
454+
const { params } = parseAutoConfig(this.local.nasConfig as string);
455+
const fcDir = params.mountDir
456+
? checkFcDir(params.mountDir, 'mountDir')
457+
: `/mnt/${functionName}`;
458+
const nasDir = params.nasDir ? params.nasDir : `${functionName}`;
459+
let serverAddr = `${mountTargetDomain}:${nasDir.startsWith('/') ? '' : '/'}${nasDir}`;
447460
if (serverAddr.length > 128) {
448461
serverAddr = serverAddr.substring(0, 128);
449462
}
@@ -454,8 +467,9 @@ nasConfig:
454467
userId: 0
455468
mountPoints:
456469
- serverAddr: ${serverAddr}
457-
mountDir: /mnt/${functionName}
458-
enableTLS: false\n`),
470+
mountDir: ${fcDir}
471+
enableTLS: false
472+
`),
459473
);
460474
this.createResource.nas = { mountTargetDomain, fileSystemId };
461475
_.set(this.local, 'nasConfig', {
@@ -464,7 +478,7 @@ nasConfig:
464478
mountPoints: [
465479
{
466480
serverAddr,
467-
mountDir: `/mnt/${functionName}`,
481+
mountDir: fcDir,
468482
enableTLS: false,
469483
},
470484
],

src/subCommands/model/index.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { OSSMountPoint, VPCConfig } from '@alicloud/fc20230330';
1414
import { MODEL_DOWNLOAD_TIMEOUT } from './constants';
1515
import { initClient } from './utils';
1616
import * as $Dev20230714 from '@alicloud/devs20230714';
17+
import { parseAutoConfig, checkFcDir } from '../../utils';
1718

1819
const commandsList = Object.keys(commandsHelp.subCommands);
1920

@@ -239,7 +240,13 @@ vpcConfig:
239240
}
240241

241242
if (nasAuto) {
242-
let serverAddr = `${mountTargetDomain}:/${functionName}`;
243+
const nasAutoConfig = parseAutoConfig(this.local.nasConfig as string);
244+
const params = nasAutoConfig?.params || {};
245+
const fcDir = params.mountDir
246+
? checkFcDir(params.mountDir, 'mountDir')
247+
: `/mnt/${functionName}`;
248+
const nasDir = params.nasDir ? params.nasDir : `${functionName}`;
249+
let serverAddr = `${mountTargetDomain}:${nasDir.startsWith('/') ? '' : '/'}${nasDir}`;
243250
if (serverAddr.length > 128) {
244251
serverAddr = serverAddr.substring(0, 128);
245252
}
@@ -250,7 +257,7 @@ groupId: 0
250257
userId: 0
251258
mountPoints:
252259
- serverAddr: ${serverAddr}
253-
mountDir: /mnt/${functionName}
260+
mountDir: ${fcDir}
254261
enableTLS: false\n`),
255262
);
256263
this.createResource.nas = { mountTargetDomain, fileSystemId };
@@ -260,7 +267,7 @@ mountPoints:
260267
mountPoints: [
261268
{
262269
serverAddr,
263-
mountDir: `/mnt/${functionName}`,
270+
mountDir: fcDir,
264271
enableTLS: false,
265272
},
266273
],

src/utils/index.ts

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,40 @@ export const isAuto = (config: unknown): boolean => {
4949
return _.toUpper(autoConfig) === 'AUTO';
5050
};
5151

52+
export const parseAutoConfig = (
53+
config: string,
54+
): { isAuto: boolean; params: Record<string, any> } => {
55+
if (!_.isString(config)) {
56+
return { isAuto: false, params: {} };
57+
}
58+
59+
const parts = config.split('|');
60+
const baseConfig = parts[0];
61+
logger.debug(`parseAutoConfig, baseConfig = ${baseConfig}`);
62+
63+
if (_.toUpper(baseConfig) === 'AUTO') {
64+
const params: Record<string, any> = {};
65+
for (let i = 1; i < parts.length; i++) {
66+
const [key, value] = parts[i].split('=');
67+
if (key && value) {
68+
const trimmedValue = value.trim();
69+
if (typeof trimmedValue === 'string') {
70+
try {
71+
params[key.trim()] = JSON.parse(trimmedValue);
72+
} catch (error) {
73+
params[key.trim()] = trimmedValue;
74+
}
75+
} else {
76+
params[key.trim()] = trimmedValue;
77+
}
78+
}
79+
}
80+
return { isAuto: true, params };
81+
}
82+
83+
return { isAuto: false, params: {} };
84+
};
85+
5286
export const isAutoVpcConfig = (config: unknown): boolean => {
5387
logger.debug(`isAutoVpcConfig, vpcConfig = ${JSON.stringify(config)}`);
5488
if (_.isString(config)) {
@@ -223,3 +257,80 @@ export function getUserAgent(userAgent: string, command: string) {
223257
}
224258
return `${function_ai}Component:fc3;Nodejs:${process.version};OS:${process.platform}-${process.arch}command:${command}`;
225259
}
260+
261+
/**
262+
* 验证并规范化路径
263+
*/
264+
export function checkFcDir(path: string, paramName = 'path'): string {
265+
if (typeof path !== 'string') {
266+
const message = `Invalid ${paramName}, expected string but got ${typeof path}`;
267+
throw new Error(message);
268+
}
269+
270+
if (!path) {
271+
const message = `Empty ${paramName}, value is required`;
272+
throw new Error(message);
273+
}
274+
275+
let normalizedPath = path.trim();
276+
277+
if (!normalizedPath.startsWith('/')) {
278+
normalizedPath = `/${normalizedPath}`;
279+
logger.debug(`${paramName} does not start with '/', prepending '/'`);
280+
}
281+
282+
if (normalizedPath.length > 1 && normalizedPath.endsWith('/')) {
283+
normalizedPath = normalizedPath.slice(0, -1);
284+
logger.debug(`${paramName} ends with '/', removing trailing '/'`);
285+
}
286+
287+
// 检查路径长度
288+
if (normalizedPath.length > 128) {
289+
const message = `${paramName} is too long (${normalizedPath.length}), maximum length is 128 characters`;
290+
throw new Error(message);
291+
}
292+
293+
// 检查不允许的系统目录前缀
294+
const forbiddenPrefixes = [
295+
'/bin',
296+
'/boot',
297+
'/dev',
298+
'/etc',
299+
'/lib',
300+
'/lib64',
301+
'/media',
302+
'/opt',
303+
'/proc',
304+
'/root',
305+
'/run',
306+
'/sbin',
307+
'/srv',
308+
'/sys',
309+
'/usr',
310+
'/var',
311+
];
312+
313+
for (const prefix of forbiddenPrefixes) {
314+
if (normalizedPath === prefix || normalizedPath.startsWith(`${prefix}/`)) {
315+
const message = `Invalid ${paramName}, ${prefix} and its subdirectories are not allowed`;
316+
throw new Error(message);
317+
}
318+
}
319+
320+
// 检查 /mnt 是否为顶级目录且没有子目录
321+
if (normalizedPath === '/mnt' || normalizedPath === '/mnt/') {
322+
const message = `Invalid ${paramName}, /mnt without subdirectory is not allowed`;
323+
throw new Error(message);
324+
}
325+
326+
// 如果路径是以 /mnt 开头,确保它有子目录
327+
if (normalizedPath.startsWith('/mnt/')) {
328+
const remainingPath = normalizedPath.substring(4);
329+
if (!remainingPath || remainingPath.split('/').every((part) => !part.trim())) {
330+
const message = `Invalid ${paramName}, /mnt path must have subdirectories`;
331+
throw new Error(message);
332+
}
333+
}
334+
335+
return normalizedPath;
336+
}

0 commit comments

Comments
 (0)