Skip to content

Commit af91ea7

Browse files
authored
feat: store code package to oss for large size of code package (#9)
#Context - store code package to oss for large size of code package - create bucket resource when needed - upload zip code to bucket - assign bucket link to fc code Refers #5 --------- Signed-off-by: seven <zilisheng1996@gmail.com>
1 parent e4d68cf commit af91ea7

File tree

11 files changed

+7722
-4432
lines changed

11 files changed

+7722
-4432
lines changed

package-lock.json

Lines changed: 7265 additions & 4421 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@
5353
"@alicloud/ros-cdk-apigateway": "^1.4.0",
5454
"@alicloud/ros-cdk-core": "^1.4.0",
5555
"@alicloud/ros-cdk-fc3": "^1.4.0",
56+
"@alicloud/ros-cdk-oss": "^1.4.0",
57+
"@alicloud/ros-cdk-ossdeployment": "^1.4.0",
5658
"@alicloud/ros-cdk-ram": "^1.4.0",
5759
"@alicloud/ros20190910": "^3.5.0",
5860
"ajv": "^8.17.1",
@@ -67,8 +69,8 @@
6769
"devDependencies": {
6870
"@types/i18n": "^0.13.12",
6971
"@types/jest": "^29.5.13",
70-
"@types/node": "^22.7.4",
7172
"@types/lodash": "^4.17.12",
73+
"@types/node": "^22.7.4",
7274
"@typescript-eslint/eslint-plugin": "^8.8.0",
7375
"@typescript-eslint/parser": "^8.8.0",
7476
"eslint": "^8.57.1",

src/common/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const CODE_ZIP_SIZE_LIMIT = 15 * 1024 * 1024;

src/common/iacHelper.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,37 @@ import path from 'node:path';
22
import fs from 'node:fs';
33
import * as ros from '@alicloud/ros-cdk-core';
44
import { ActionContext } from '../types';
5+
import * as ossDeployment from '@alicloud/ros-cdk-ossdeployment';
6+
import crypto from 'node:crypto';
57

68
export const resolveCode = (location: string): string => {
79
const filePath = path.resolve(process.cwd(), location);
810
const fileContent = fs.readFileSync(filePath);
911

1012
return fileContent.toString('base64');
1113
};
14+
export const readCodeSize = (location: string): number => {
15+
const filePath = path.resolve(process.cwd(), location);
16+
const stats = fs.statSync(filePath);
17+
return stats.size;
18+
};
19+
20+
export const getFileSource = (
21+
fcName: string,
22+
location: string,
23+
): { source: ossDeployment.ISource; objectKey: string } => {
24+
const filePath = path.resolve(process.cwd(), location);
25+
if (fs.lstatSync(filePath).isDirectory()) {
26+
throw new Error('The provided path is a directory, not a file.');
27+
}
28+
29+
const hash = crypto.createHash('md5').update(fs.readFileSync(filePath)).digest('hex');
30+
31+
const objectKey = `${fcName}/${hash}.${filePath.split('.').pop()}`;
32+
const source = ossDeployment.Source.asset(filePath, {}, objectKey);
33+
34+
return { source, objectKey };
35+
};
1236

1337
const evalCtx = (value: string, ctx: ActionContext): string => {
1438
const containsStage = value.match(/\$\{ctx.\w+}/);

src/common/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ export * from './getVersion';
44
export * from './rosClient';
55
export * from './actionContext';
66
export * from './iacHelper';
7+
export * from './constants';

src/stack/iacStack.ts

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,18 @@ import * as ros from '@alicloud/ros-cdk-core';
22
import { RosParameterType } from '@alicloud/ros-cdk-core';
33
import { ActionContext, EventTypes, ServerlessIac } from '../types';
44
import * as fc from '@alicloud/ros-cdk-fc3';
5+
import { RosFunction } from '@alicloud/ros-cdk-fc3/lib/fc3.generated';
56
import * as ram from '@alicloud/ros-cdk-ram';
67
import * as agw from '@alicloud/ros-cdk-apigateway';
7-
import { replaceReference, resolveCode } from '../common';
8+
import * as oss from '@alicloud/ros-cdk-oss';
9+
import * as ossDeployment from '@alicloud/ros-cdk-ossdeployment';
10+
import {
11+
CODE_ZIP_SIZE_LIMIT,
12+
getFileSource,
13+
readCodeSize,
14+
replaceReference,
15+
resolveCode,
16+
} from '../common';
817

918
export class IacStack extends ros.Stack {
1019
private readonly service: string;
@@ -41,7 +50,45 @@ export class IacStack extends ros.Stack {
4150
replaceReference(`${this.service} stack`, context),
4251
);
4352

53+
const fileSources = iac.functions
54+
.filter(({ code }) => readCodeSize(code) > CODE_ZIP_SIZE_LIMIT)
55+
.map(({ code, name }) => ({ fcName: name, ...getFileSource(name, code) }));
56+
57+
let destinationBucket: oss.Bucket;
58+
if (fileSources.length > 0) {
59+
// creat oss to store code
60+
destinationBucket = new oss.Bucket(
61+
this,
62+
replaceReference(`${this.service}_artifacts_bucket`, context),
63+
{
64+
bucketName: replaceReference(`${this.service}-artifacts-bucket`, context),
65+
serverSideEncryptionConfiguration: { sseAlgorithm: 'KMS' },
66+
},
67+
true,
68+
);
69+
new ossDeployment.BucketDeployment(
70+
this,
71+
`${this.service}_artifacts_code_deployment`,
72+
{
73+
sources: fileSources.map(({ source }) => source),
74+
destinationBucket,
75+
timeout: 300,
76+
logMonitoring: false, // 是否开启日志监控,设为false则不开启
77+
},
78+
true,
79+
);
80+
}
81+
4482
iac.functions.forEach((fnc) => {
83+
let code: RosFunction.CodeProperty = {
84+
zipFile: resolveCode(fnc.code),
85+
};
86+
if (readCodeSize(fnc.code) > CODE_ZIP_SIZE_LIMIT) {
87+
code = {
88+
ossBucketName: destinationBucket.attrName,
89+
ossObjectName: fileSources.find(({ fcName }) => fcName === fnc.name)?.objectKey,
90+
};
91+
}
4592
new fc.RosFunction(
4693
this,
4794
fnc.key,
@@ -52,9 +99,7 @@ export class IacStack extends ros.Stack {
5299
memorySize: replaceReference(fnc.memory, context),
53100
timeout: replaceReference(fnc.timeout, context),
54101
environmentVariables: replaceReference(fnc.environment, context),
55-
code: {
56-
zipFile: resolveCode(fnc.code),
57-
},
102+
code,
58103
},
59104
true,
60105
);

tests/common/iacHelper.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as ossDeployment from '@alicloud/ros-cdk-ossdeployment';
2+
import { getFileSource } from '../../src/common';
3+
import fs from 'node:fs';
4+
5+
jest.mock('@alicloud/ros-cdk-ossdeployment');
6+
7+
const fcName = 'testFunction';
8+
const location = 'tests/fixtures/artifacts/artifact.zip';
9+
10+
describe('getFileSource', () => {
11+
it('should return the correct ossDeployment source', () => {
12+
getFileSource(fcName, location);
13+
expect(ossDeployment.Source.asset).toHaveBeenCalledWith(
14+
`${process.cwd()}/${location}`,
15+
{},
16+
`${fcName}/50861cd99a3a678356030f5f189300af.zip`,
17+
);
18+
});
19+
20+
it('should throw an error if the path is a directory', () => {
21+
jest.spyOn(fs, 'lstatSync').mockReturnValue({ isDirectory: () => true } as fs.Stats);
22+
23+
expect(() => getFileSource(fcName, location)).toThrow(
24+
'The provided path is a directory, not a file.',
25+
);
26+
});
27+
});

tests/fixtures/artifacts/artifact.zip

481 Bytes
Binary file not shown.
20.8 MB
Binary file not shown.

0 commit comments

Comments
 (0)