Skip to content

Commit

Permalink
feat: deployment action calling aliyun ok
Browse files Browse the repository at this point in the history
Signed-off-by: seven <[email protected]>
  • Loading branch information
Blankll committed Sep 21, 2024
1 parent e33b209 commit cd0a587
Show file tree
Hide file tree
Showing 11 changed files with 513 additions and 28 deletions.
334 changes: 328 additions & 6 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@
"function"
],
"dependencies": {
"@alicloud/openapi-client": "^0.4.11",
"@alicloud/ros-cdk-core": "^1.2.0",
"@alicloud/ros-cdk-fc": "^1.2.0",
"@alicloud/ros20190910": "^3.4.3",
"ajv": "^8.17.1",
"chalk": "^4.1.2",
"commander": "^11.1.0",
Expand Down
10 changes: 7 additions & 3 deletions src/commands/deploy.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { deployStack } from '../stack';
import { printer } from '../common';
import { parseYaml } from '../iac';
import { constructActionContext } from '../common/actionContext';

export const deploy = (location?: string) => {
export const deploy = async (stackName: string, options: { location: string }) => {
const context = constructActionContext({ location: options.location });
printer.info(`Deploying stack context: ${JSON.stringify(context)}...`);
printer.info('Validating yaml...');
const iac = parseYaml(location);
const iac = parseYaml(context.iacLocation);
printer.success('Yaml is valid! 🎉');

printer.info('Deploying stack...');
deployStack(iac);
await deployStack(stackName, iac, context);

printer.success('Stack deployed! 🎉');
};
14 changes: 8 additions & 6 deletions src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,21 @@ program
});

program
.command('validate [location]')
.command('validate [stackName]')
.description('validate serverless Iac yaml')
.action((location) => {
.option('-f, --file <path>', 'specify the yaml file')
.action((stackName, options) => {
logger.debug('log command info');
validate(location);
validate(options.file);
});

program
.command('deploy [location]')
.command('deploy <stackName>')
.description('deploy serverless Iac yaml')
.action((location) => {
.option('-f, --file <path>', 'specify the yaml file')
.action(async (stackName, options) => {
logger.debug('log command info');
deploy(location);
await deploy(stackName, { location: options.file });
});

program.parse();
4 changes: 3 additions & 1 deletion src/commands/validate.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { parseYaml } from '../iac';
import { printer } from '../common';
import { constructActionContext } from '../common/actionContext';

export const validate = (location?: string) => {
parseYaml(location);
const context = constructActionContext({ location });
parseYaml(context.iacLocation);
printer.success('Yaml is valid! 🎉');
};
25 changes: 25 additions & 0 deletions src/common/actionContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ActionContext } from '../types';
import path from 'node:path';

export const constructActionContext = (config?: {
region?: string;
account?: string;
accessKeyId?: string;
accessKeySecret?: string;
securityToken?: string;
location?: string;
}): ActionContext => {
return {
region:
config?.region ?? process.env.ROS_REGION_ID ?? process.env.ALIYUN_REGION ?? 'cn-hangzhou',
accessKeyId: config?.accessKeyId ?? (process.env.ALIYUN_ACCESS_KEY_ID as string),
accessKeySecret: config?.accessKeySecret ?? (process.env.ALIYUN_ACCESS_KEY_SECRET as string),
securityToken: config?.securityToken ?? process.env.ALIYUN_SECURITY_TOKEN,
iacLocation: (() => {
const projectRoot = path.resolve(process.cwd());
return config?.location
? path.resolve(projectRoot, config?.location)
: path.resolve(projectRoot, 'serverless-insight.yml');
})(),
};
};
1 change: 1 addition & 0 deletions src/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from './printer';
export * from './provider';
export * from './logger';
export * from './getVersion';
export * from './rosClient';
102 changes: 102 additions & 0 deletions src/common/rosClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import Util from '@alicloud/tea-util';
import ROS20190910, {
CreateStackRequest,
CreateStackRequestParameters,
CreateStackRequestTags,
ListStacksRequest,
} from '@alicloud/ros20190910';
import { Config } from '@alicloud/openapi-client';
import { ActionContext } from '../types';
import { printer } from './printer';

const client = new ROS20190910(
new Config({
accessKeyId: process.env.ALIYUN_ACCESS_KEY_ID,
accessKeySecret: process.env.ALIYUN_ACCESS_KEY_SECRET,
regionId: process.env.ALIYUN_REGION,
disableRollback: false,
}),
);

const createStack = async (stackName: string, templateBody: unknown, context: ActionContext) => {
const parameters = context.parameters?.map(
(parameter) =>
new CreateStackRequestParameters({
parameterKey: Util.assertAsString(parameter.key),
parameterValue: Util.assertAsString(parameter.value),
}),
);

const createStackRequest = new CreateStackRequest({
regionId: context.region,
stackName,
templateBody: JSON.stringify(templateBody),
parameters,
tags: context.tags?.map((tag) => new CreateStackRequestTags(tag)),
});

console.log('createStackRequest:', createStackRequest);

const response = await client.createStack(createStackRequest);
console.log(`创建中,资源栈ID:${response.body?.stackId}`);
return response.body?.stackId;
};

const updateStack = async (stackName: string, templateBody: unknown, context: ActionContext) => {
const parameters = context.parameters?.map(
(parameter) =>
new CreateStackRequestParameters({
parameterKey: Util.assertAsString(parameter.key),
parameterValue: Util.assertAsString(parameter.value),
}),
);

const createStackRequest = new CreateStackRequest({
stackName,
templateBody,
parameters,
});

const response = await client.updateStack(createStackRequest);
console.log(`更新中,资源栈ID:${response.body?.stackId}`);
return response.body?.stackId;
};

const getStackByName = async (stackName: string, region: string) => {
const result = await client.listStacks(
new ListStacksRequest({
regionId: region,
pageSize: 10,
pageNumber: 1,
stackName: [stackName],
}),
);

if (result.statusCode === 200) {
return result.body?.stacks?.[0];
} else {
return null;
}
};

export const rosStackDeploy = async (
stackName: string,
templateBody: unknown,
context: ActionContext,
) => {
const stackInfo = await getStackByName(stackName, context.region);
if (stackInfo) {
const { Status: stackStatus } = stackInfo;
if (stackStatus?.indexOf('IN_PROGRESS') >= 0) {
printer.error(`fail to update stack, because stack status is ${stackStatus}`);
throw new Error(`fail to update stack, because stack status is ${stackStatus}`);
}

printer.info(`Update stack: ${stackName} deploying... `);
return await updateStack(stackName, templateBody, context);
} else {
// create stack
printer.info(`Create stack: ${stackName} deploying... `);
return await createStack(stackName, templateBody, context);
}
};
10 changes: 2 additions & 8 deletions src/iac/parse.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { parse } from 'yaml';
import { existsSync, readFileSync } from 'node:fs';
import { IacFunction, RawServerlessIac, ServerlessIac, Event } from '../types';
import { Event, IacFunction, RawServerlessIac, ServerlessIac } from '../types';
import { validateYaml } from './iacSchema';
import path from 'node:path';

const mapToArr = (obj: Record<string, Record<string, unknown> | string>) => {
return Object.entries(obj).map(([key, value]) =>
Expand All @@ -29,12 +28,7 @@ const transformYaml = (iacJson: RawServerlessIac): ServerlessIac => {
};
};

export const parseYaml = (location?: string): ServerlessIac => {
const projectRoot = path.resolve(process.cwd());
const yamlPath = location
? path.resolve(projectRoot, location)
: path.resolve(projectRoot, 'serverless-insight.yml');

export const parseYaml = (yamlPath: string): ServerlessIac => {
validateExistence(yamlPath);

const yamlContent = readFileSync(yamlPath, 'utf8');
Expand Down
29 changes: 25 additions & 4 deletions src/stack/deploy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as ros from '@alicloud/ros-cdk-core';
import * as fc from '@alicloud/ros-cdk-fc';
import { ServerlessIac } from '../types';
import { ActionContext, ServerlessIac } from '../types';
import { printer, rosStackDeploy } from '../common';

export class IacStack extends ros.Stack {
constructor(scope: ros.Construct, iac: ServerlessIac, props?: ros.StackProps) {
Expand Down Expand Up @@ -30,9 +31,29 @@ export class IacStack extends ros.Stack {
}
}

export const deployStack = (iac: ServerlessIac) => {
console.log(`Deploying stack... ${JSON.stringify(iac)}`);
const generateStackTemplate = (stackName: string, iac: ServerlessIac) => {
const app = new ros.App();
new IacStack(app, iac);
app.synth();

const assembly = app.synth();
const stackArtifact = assembly.getStackByName(stackName);
const parameters = Object.entries(stackArtifact.parameters).map(([key, value]) => ({
key,
value,
}));

return { template: stackArtifact.template, parameters };
};

export const deployStack = async (
stackName: string,
iac: ServerlessIac,
context: ActionContext,
) => {
printer.info(`Deploying stack... ${JSON.stringify(iac)}`);

const { template, parameters } = generateStackTemplate(stackName, iac);
console.log('Generated ROS YAML:', JSON.stringify({ template, parameters }));
await rosStackDeploy(stackName, template, { ...context, parameters });
printer.info(`Stack deployed! 🎉`);
};
10 changes: 10 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,13 @@ export type ServerlessIac = {
functions: Array<IacFunction>;
events: Array<Event>;
};

export type ActionContext = {
region: string;
accessKeyId: string;
accessKeySecret: string;
securityToken?: string;
iacLocation: string;
parameters?: Array<{ key: string; value: string }>;
tags?: Array<{ key: string; value: string }>;
};

0 comments on commit cd0a587

Please sign in to comment.