Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions __tests__/ut/commands/build/impl/baseBuilder_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ describe('Builder', () => {
const builderWithCustomContainer = new TestBuilder(inputsWithCustomContainer);

(FC.isCustomContainerRuntime as jest.Mock).mockReturnValue(true);
(FC.getContainerImage as jest.Mock).mockReturnValue('custom-image:latest');

const image = await builderWithCustomContainer.getRuntimeBuildImage();
expect(image).toBe('custom-image:latest');
Expand All @@ -300,6 +301,7 @@ describe('Builder', () => {
const builderWithCustomContainer = new TestBuilder(inputsWithCustomContainer);

(FC.isCustomContainerRuntime as jest.Mock).mockReturnValue(true);
(FC.getContainerImage as jest.Mock).mockReturnValue('');
(_.isEmpty as any).mockReturnValue(true);

await expect(builderWithCustomContainer.getRuntimeBuildImage()).rejects.toThrow(
Expand Down
11 changes: 11 additions & 0 deletions __tests__/ut/commands/deploy/impl/function_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,9 @@ describe('Service', () => {
customContainerConfig: {},
} as IFunction;

// Mock FC.getContainerImage
(FC.getContainerImage as jest.Mock).mockReturnValue(undefined);

await expect((service as any)._pushImage()).rejects.toThrow(
'CustomContainerRuntime must have a valid image URL',
);
Expand All @@ -455,6 +458,11 @@ describe('Service', () => {
customContainerConfig: { image: 'registry.cn-hangzhou.aliyuncs.com/test/image' },
} as IFunction;

// Mock FC.getContainerImage
(FC.getContainerImage as jest.Mock).mockReturnValue(
'registry.cn-hangzhou.aliyuncs.com/test/image',
);

// Mock Acr.isAcrRegistry
Acr.isAcrRegistry = jest.fn().mockReturnValue(true);

Expand All @@ -475,6 +483,9 @@ describe('Service', () => {
customContainerConfig: { image: 'docker.io/test/image' },
} as IFunction;

// Mock FC.getContainerImage
(FC.getContainerImage as jest.Mock).mockReturnValue('docker.io/test/image');

// Mock Acr.isAcrRegistry
Acr.isAcrRegistry = jest.fn().mockReturnValue(false);

Expand Down
23 changes: 23 additions & 0 deletions __tests__/ut/resources/fc/impl/utils_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
getRemoteResourceConfig,
computeLocalAuto,
getCustomEndpoint,
getContainerImage,
} from '../../../../../src/resources/fc/impl/utils';
import { INasConfig, IVpcConfig, ILogConfig, IOssMountConfig } from '../../../../../src/interface';
import * as utils from '../../../../../src/utils';
Expand Down Expand Up @@ -68,6 +69,28 @@ describe('utils', () => {
});
});

describe('getContainerImage', () => {
it('should prefer microSandboxConfig.image over customContainerConfig.image', () => {
const result = getContainerImage({
microSandboxConfig: { image: 'registry/sandbox:v1' },
customContainerConfig: { image: 'registry/container:v1' },
});
expect(result).toBe('registry/sandbox:v1');
});

it('should fall back to customContainerConfig.image', () => {
const result = getContainerImage({
customContainerConfig: { image: 'registry/container:v1' },
});
expect(result).toBe('registry/container:v1');
});

it('should return undefined when no image is configured', () => {
expect(getContainerImage({})).toBeUndefined();
expect(getContainerImage({ customContainerConfig: { image: '' } })).toBeUndefined();
});
});

describe('getRemoteResourceConfig', () => {
it('should extract remote resource configurations correctly', () => {
const mockRemote = {
Expand Down
2 changes: 1 addition & 1 deletion publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Type: Component
Name: fc3
Provider:
- 阿里云
Version: 0.1.24
Version: 0.1.25
Description: 阿里云函数计算全生命周期管理
HomePage: https://github.com/devsapp/fc3
Organization: 阿里云函数计算(FC)
Expand Down
11 changes: 8 additions & 3 deletions src/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,14 @@ export default class Base {
_.set(inputs, 'props.endpoint', argvEndpoint);
}
// fc组件镜像 trim 左右空格
const image = _.get(inputs, 'props.customContainerConfig.image');
if (!_.isEmpty(image)) {
_.set(inputs, 'props.customContainerConfig.image', _.trim(image));
for (const imagePath of [
'props.microSandboxConfig.image',
'props.customContainerConfig.image',
]) {
const image = _.get(inputs, imagePath);
if (!_.isEmpty(image)) {
_.set(inputs, imagePath, _.trim(image));
}
}

const role = _.get(inputs, 'props.role');
Expand Down
1 change: 1 addition & 0 deletions src/interface/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export interface ILogConfig {
}

export interface IMicroSandboxConfig {
image?: string;
osType?: string;
readyCommand?: string;
startCommand?: string;
Expand Down
19 changes: 18 additions & 1 deletion src/resources/fc/impl/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import _ from 'lodash';
import { INasConfig, IVpcConfig, ILogConfig, Runtime, IOssMountConfig } from '../../../interface';
import {
INasConfig,
IVpcConfig,
ILogConfig,
Runtime,
IOssMountConfig,
IFunction,
} from '../../../interface';
import { isAuto, isAutoVpcConfig } from '../../../utils';
import logger from '../../../logger';
import * as fs from 'fs';
Expand All @@ -10,6 +17,16 @@
return runtime === Runtime['custom-container'] || runtime === Runtime['micro-sandbox'];
}

/**
* microSandboxConfig.image 优先级高于 customContainerConfig.image
*/
export function getContainerImage(
props: Pick<IFunction, 'microSandboxConfig' | 'customContainerConfig'>,
): string | undefined {
const image = props?.microSandboxConfig?.image || props?.customContainerConfig?.image;
return _.isEmpty(image) ? undefined : image;
}

export function isCustomRuntime(runtime: string): boolean {
return (
runtime === Runtime.custom ||
Expand Down Expand Up @@ -45,7 +62,7 @@
if (stat.isDirectory()) {
continue;
}
const newMode = stat.mode | 0o111;

Check warning on line 65 in src/resources/fc/impl/utils.ts

View workflow job for this annotation

GitHub Actions / check-format

Unexpected use of '|'
fs.chmodSync(filePath, newMode);
logger.info(`Set executable permission for: ${filePath}`);
} catch (fileError) {
Expand Down
34 changes: 18 additions & 16 deletions src/resources/fc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,12 @@ import {
isFunctionStateWaitTimedOut,
isFunctionScalingConfigError,
} from './error-code';
import { isCustomContainerRuntime, isCustomRuntime, computeLocalAuto } from './impl/utils';
import {
isCustomContainerRuntime,
isCustomRuntime,
computeLocalAuto,
getContainerImage,
} from './impl/utils';
import replaceFunctionConfig from './impl/replace-function-config';
import { IAlias } from '../../interface/cli-config/alias';
import { TriggerType } from '../../interface/base';
Expand All @@ -79,6 +84,7 @@ export default class FC extends FC_Client {
static computeLocalAuto = computeLocalAuto;
static isCustomContainerRuntime = isCustomContainerRuntime;
static isCustomRuntime = isCustomRuntime;
static getContainerImage = getContainerImage;
static replaceFunctionConfig = replaceFunctionConfig;

async untilFunctionStateOK(config: IFunction, reason: string, skipAccelerationWait?: boolean) {
Expand All @@ -93,34 +99,35 @@ export default class FC extends FC_Client {
const retryContainerAccelerated = FC.isCustomContainerRuntime(config.runtime);
// 部署镜像需要重试 3min, 直到达到!(State == Pending || LastUpdateStatus == InProgress)
if (retryContainerAccelerated) {
const image = getContainerImage(config);
if (skipAccelerationWait) {
logger.info(
`Skip waiting for ${config.customContainerConfig.image} optimization. The function will be available for invocation once the image acceleration process is complete.`,
`Skip waiting for ${image} optimization. The function will be available for invocation once the image acceleration process is complete.`,
);
return;
}
console.log('');
if (reason === 'CREATE') {
if (isAppCenter()) {
logger.info(
`${config.customContainerConfig.image} optimization to be ready, the function will be available for invocation once this process is complete`,
`${image} optimization to be ready, the function will be available for invocation once this process is complete`,
);
} else {
logger.spin(
'checking',
`${config.customContainerConfig.image} `,
`${image} `,
`optimization to be ready, the function will be available for invocation once this process is complete ...`,
);
}
} else if (reason === 'UPDATE') {
if (isAppCenter()) {
logger.info(
`${config.customContainerConfig.image} optimization to be ready, function calls will be updated to the latest deployed version once the image optimization process is complete ...`,
`${image} optimization to be ready, function calls will be updated to the latest deployed version once the image optimization process is complete ...`,
);
} else {
logger.spin(
'checking',
`${config.customContainerConfig.image}`,
`${image}`,
`optimization to be ready, function calls will be updated to the latest deployed version once the image optimization process is complete ...`,
);
}
Expand All @@ -145,16 +152,14 @@ export default class FC extends FC_Client {
await sleep(retryInterval);
if (isAppCenter()) {
logger.info(
`${
config.customContainerConfig.image
} optimization is not ready, function state=${state}, lastUpdateStatus=${lastUpdateStatus}, waiting ${
`${image} optimization is not ready, function state=${state}, lastUpdateStatus=${lastUpdateStatus}, waiting ${
(new Date().getTime() - startTime) / 1000
} seconds...`,
);
} else {
logger.spin(
'checking',
`${config.customContainerConfig.image}`,
`${image}`,
`optimization is not ready, function state=${state}, lastUpdateStatus=${lastUpdateStatus}, waiting ${
(new Date().getTime() - startTime) / 1000
} seconds...`,
Expand All @@ -172,13 +177,9 @@ export default class FC extends FC_Client {
await sleep(retryInterval);
} else {
if (isAppCenter()) {
logger.info(`${config.customContainerConfig.image} optimization is ready`);
logger.info(`${image} optimization is ready`);
} else {
logger.spin(
'checked',
`${config.customContainerConfig.image}`,
`optimization is ready`,
);
logger.spin('checked', `${image}`, `optimization is ready`);
}
break;
}
Expand Down Expand Up @@ -290,6 +291,7 @@ export default class FC extends FC_Client {
functionName: config.functionName,
code: config.code,
customContainerConfig: config.customContainerConfig,
microSandboxConfig: config.microSandboxConfig,
} as any;
} else if (type === 'config') {
_.unset(config, 'code');
Expand Down
18 changes: 16 additions & 2 deletions src/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,9 @@
},
"IMicroSandboxConfig": {
"properties": {
"image": {
"type": "string"
},
"osType": {
"type": "string"
},
Expand Down Expand Up @@ -1454,8 +1457,19 @@
"required": [
"region",
"functionName",
"runtime",
"customContainerConfig"
"runtime"
],
"anyOf": [
{
"required": [
"microSandboxConfig"
]
},
{
"required": [
"customContainerConfig"
]
}
]
},
"else": {
Expand Down
2 changes: 1 addition & 1 deletion src/subCommands/build/impl/baseBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export abstract class Builder {
async getRuntimeBuildImage(): Promise<string> {
let image: string;
if (FC.isCustomContainerRuntime(this.getRuntime())) {
image = this.getProps().customContainerConfig?.image;
image = FC.getContainerImage(this.getProps());
if (_.isEmpty(image)) {
throw new Error('image must be set in custom-container runtime');
}
Expand Down
4 changes: 2 additions & 2 deletions src/subCommands/deploy/impl/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ export default class Service extends Base {
// custom-container 检查 s.yaml 中 image 是否存在 acr 中, 如果存在, 则弹出交互提示
// --skip-push 则不用提示
if (FC.isCustomContainerRuntime(this.local.runtime)) {
const { image } = this.local.customContainerConfig || {};
const image = FC.getContainerImage(this.local);
if (_.isNil(image)) {
throw new Error('CustomContainerRuntime must have a valid image URL');
}
Expand Down Expand Up @@ -256,7 +256,7 @@ export default class Service extends Base {
logger.debug(`skip push is ${this.skipPush}`);
return;
}
const { image } = this.local.customContainerConfig || {};
const image = FC.getContainerImage(this.local);
if (_.isNil(image)) {
throw new Error('CustomContainerRuntime must have a valid image URL');
}
Expand Down
2 changes: 1 addition & 1 deletion src/subCommands/local/impl/baseLocal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ export class BaseLocal {
let image: string;

if (this.isCustomContainerRuntime()) {
image = this.inputs.props.customContainerConfig.image;
image = FC.getContainerImage(this.inputs.props);
logger.debug(`use fc docker CustomContainer image: ${image}`);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
} else if (fcDockerUseImage) {
image = fcDockerUseImage;
Expand Down
Loading