Skip to content

Commit c51ab7b

Browse files
committed
feat: 部署函数支持添加云梯默认标签(运营部门,运营产品,负责人)
1 parent b525006 commit c51ab7b

File tree

10 files changed

+147
-17
lines changed

10 files changed

+147
-17
lines changed

package-lock.json

Lines changed: 16 additions & 9 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 & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "tencent-component-toolkit",
3-
"version": "2.24.2",
3+
"version": "2.24.3",
44
"description": "Tencent component toolkit",
55
"main": "lib/index.js",
66
"types": "lib/index.d.ts",
@@ -66,12 +66,12 @@
6666
"@semantic-release/git": "^9.0.0",
6767
"@semantic-release/npm": "^7.0.4",
6868
"@semantic-release/release-notes-generator": "^9.0.1",
69+
"@types/axios": "^0.14.0",
6970
"@types/react-grid-layout": "^1.1.2",
7071
"@types/uuid": "^8.3.1",
7172
"@typescript-eslint/eslint-plugin": "^4.14.0",
7273
"@typescript-eslint/parser": "^4.14.0",
7374
"@ygkit/secure": "^0.0.3",
74-
"axios": "^0.21.0",
7575
"dotenv": "^8.2.0",
7676
"eslint": "^7.18.0",
7777
"eslint-config-prettier": "^6.10.0",
@@ -90,6 +90,7 @@
9090
"@types/jest": "^26.0.20",
9191
"@types/node": "^14.14.31",
9292
"@ygkit/request": "^0.1.8",
93+
"axios": "^0.21.0",
9394
"camelcase": "^6.2.0",
9495
"cos-nodejs-sdk-v5": "^2.9.20",
9596
"dayjs": "^1.10.4",

src/modules/cam/apis.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const ACTIONS = [
88
'CreateRole',
99
'GetRole',
1010
'DeleteRole',
11+
'GetUserAppId',
1112
] as const;
1213

1314
export type ActionType = typeof ACTIONS[number];

src/modules/cam/index.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { ActionType } from './apis';
22
import { CapiCredentials, RegionType, ApiServiceType } from './../interface';
33
import { Capi } from '@tencent-sdk/capi';
44
import APIS from './apis';
5+
import { getYunTiApiUrl } from '../../utils';
6+
import axios from 'axios';
57

68
/** CAM (访问管理)for serverless */
79
export default class Cam {
@@ -112,4 +114,54 @@ export default class Cam {
112114
async CheckSCFExcuteRole() {
113115
return this.isRoleExist('QCS_SCFExcuteRole');
114116
}
117+
118+
/** 查询用户AppId */
119+
async GetUserAppId(): Promise<{ OwnerUin: string; AppId: string; Uin: string }> {
120+
try {
121+
return this.request({
122+
Action: 'GetUserAppId',
123+
});
124+
} catch (error) {
125+
return {
126+
OwnerUin: '',
127+
AppId: '',
128+
Uin: '',
129+
};
130+
}
131+
}
132+
133+
/**
134+
* checkYunTi 检查是否是云梯账号
135+
* @returns {boolean} true: 是云梯账号; false: 非云梯账号
136+
*/
137+
async checkYunTi(): Promise<boolean> {
138+
let isYunTi = false;
139+
const { OwnerUin: uin } = await this.GetUserAppId();
140+
try {
141+
const params = JSON.stringify({
142+
id: '1',
143+
jsonrpc: '2.0',
144+
method: 'checkOwnUin',
145+
params: { ownUin: [uin] },
146+
});
147+
const apiUrl = getYunTiApiUrl();
148+
const res = await axios.post(apiUrl, params, {
149+
headers: { 'content-type': 'application/json' },
150+
});
151+
if (res?.data?.error?.message) {
152+
throw new Error(res.data.error.message);
153+
} else {
154+
isYunTi =
155+
res?.data?.result?.data &&
156+
res.data.result.data?.some(
157+
(item: { ownUin: string; appId: string }) => item?.ownUin === uin,
158+
);
159+
console.log('check yunTi ownUin:', isYunTi);
160+
}
161+
} catch (error) {
162+
isYunTi = false;
163+
console.log('checkYunTiOwnUin error:', error);
164+
}
165+
return isYunTi;
166+
}
115167
}

src/modules/scf/index.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { ActionType } from './apis';
33
import { RegionType, ApiServiceType, CapiCredentials } from './../interface';
44
import { Capi } from '@tencent-sdk/capi';
55
import { ApiTypeError } from '../../utils/error';
6-
import { deepClone, strip } from '../../utils';
6+
import { deepClone, formatInputTags, strip } from '../../utils';
77
import TagsUtils from '../tag/index';
88
import ApigwUtils from '../apigw';
99
import CONFIGS from './config';
@@ -252,13 +252,15 @@ export default class Scf {
252252
credentials: this.credentials,
253253
region: this.region,
254254
});
255+
const tags: any = trigger?.parameters?.tags ?? trigger?.tags ?? funcInfo.Tags ?? [];
255256
const triggerOutput = await triggerInstance.create({
256257
scf: this,
257258
region: this.region,
258259
inputs: {
259260
namespace: funcInfo.Namespace,
260261
functionName: funcInfo.FunctionName,
261262
...trigger,
263+
tags: formatInputTags(tags),
262264
},
263265
});
264266

@@ -457,4 +459,14 @@ export default class Scf {
457459
const logs = await this.scf.getLogs(inputs);
458460
return logs;
459461
}
462+
463+
checkAddedYunTiTags(tags: Array<{ [key: string]: string }>): boolean {
464+
const formatTags = formatInputTags(tags);
465+
const result =
466+
formatTags?.length > 0 &&
467+
['运营部门', '运营产品', '负责人'].every((tagKey) =>
468+
formatTags.some((item) => item.key === tagKey && !!item.value),
469+
);
470+
return result;
471+
}
460472
}

src/modules/scf/interface.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ export interface TriggerType {
7878
TriggerName?: string;
7979
Qualifier?: string;
8080
compared?: boolean;
81+
tags?: object;
82+
parameters?: any;
8183
}
8284

8385
export type OriginTriggerType = {

src/modules/scf/utils.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,8 @@ export const formatInputs = (inputs: ScfCreateFunctionInputs) => {
6161
// 监听端口: -1 表示 job镜像,0 ~ 65526 表示webServer镜像
6262
if (imageConfig.imagePort) {
6363
functionInputs.Code!.ImageConfig!.ImagePort =
64-
Number.isInteger(imageConfig?.imagePort) &&
65-
imageConfig?.imagePort >= -1 &&
66-
imageConfig?.imagePort <= 65535
67-
? imageConfig.imagePort
64+
Number.isInteger(imageConfig?.imagePort) && imageConfig?.imagePort === -1
65+
? -1
6866
: WebServerImageDefaultPort;
6967
}
7068
} else {

src/modules/triggers/apigw.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ export default class ApigwTrigger extends BaseTrigger<ApigwTriggerInputsParams>
147147
funcInfo?: FunctionInfo;
148148
inputs: TriggerInputs<ApigwTriggerInputsParams>;
149149
}) {
150-
const { parameters, isAutoRelease } = inputs;
150+
const { parameters, isAutoRelease, tags } = inputs;
151151
const {
152152
oldState,
153153
protocols,
@@ -192,6 +192,7 @@ export default class ApigwTrigger extends BaseTrigger<ApigwTriggerInputsParams>
192192
method: endpoints[0].method ?? 'ANY',
193193
},
194194
created: !!parameters?.created,
195+
tags,
195196
};
196197
const triggerKey = this.getKey(triggerInputs);
197198

src/modules/triggers/interface/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ApigwDeployInputs, ApiEndpoint } from '../../apigw/interface';
2+
import { TagInput } from '../../interface';
23

34
export interface ApigwTriggerRemoveScfTriggerInputs {
45
serviceId: string;
@@ -129,6 +130,9 @@ export interface TriggerInputs<P extends TriggerInputsParams = TriggerInputsPara
129130

130131
// 是否自动发布服务(API 网关特有)
131132
isAutoRelease?: boolean;
133+
134+
// 标签列表
135+
tags?: TagInput[];
132136
}
133137

134138
export interface TriggerDetail {

src/utils/index.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import path from 'path';
33
import camelCase from 'camelcase';
44
import { PascalCase } from 'type-fest';
55
import { CamelCasedProps, PascalCasedProps } from '../modules/interface';
6+
import crypto from 'crypto';
67

78
// TODO: 将一些库换成 lodash
89

@@ -273,3 +274,54 @@ export const getQcsResourceId = (service: string, region: string, uin: string, s
273274
// 云资源六段式
274275
return `qcs::${service}:${region}:uin/${uin}:${suffix}`;
275276
};
277+
278+
/**
279+
* hmacSha1 加密HmacSHA1
280+
* @param text 加密文本
281+
* @param key 加密密钥
282+
* @returns
283+
*/
284+
export const hmacSha1 = (text: string, key: string) => {
285+
return crypto.createHmac('sha1', key).update(text).digest('hex');
286+
};
287+
288+
/**
289+
* getYunTiApiUrl 查询云梯API地址
290+
* @returns 云梯API地址
291+
*/
292+
export const getYunTiApiUrl = (): string => {
293+
const apiKey = process.env.SLS_YUNTI_API_KEY || '';
294+
const apiSecret = process.env.SLS_YUNTI_API_SECRET || '';
295+
const apiUrl = process.env.SLS_YUNTI_API_URL;
296+
const timeStamp = Math.floor(Date.now() / 1000);
297+
const apiSign = hmacSha1(`${timeStamp}${apiKey}`, apiSecret);
298+
const url = `${apiUrl}?api_key=${apiKey}&api_ts=${timeStamp}&api_sign=${apiSign}`;
299+
return url;
300+
};
301+
302+
/**
303+
* formatInputTags 格式化输入标签
304+
*/
305+
export const formatInputTags = (
306+
input: Array<any> | { [key: string]: string },
307+
): { key: string; value: string }[] => {
308+
let tags: { key: string; value: string }[];
309+
if (Array.isArray(input)) {
310+
tags = input.map((item) => {
311+
return {
312+
key: item?.key ?? item?.Key ?? '',
313+
value: item?.value ?? item?.Value ?? '',
314+
};
315+
});
316+
} else if (typeof input === 'object' && input) {
317+
tags = Object.entries(input).map(([key, value]) => {
318+
return {
319+
key: (key ?? '').toString(),
320+
value: (value ?? '').toString(),
321+
};
322+
});
323+
} else {
324+
tags = undefined as any;
325+
}
326+
return tags;
327+
};

0 commit comments

Comments
 (0)