@cloudbase/cli 1.12.7-alpha.4 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/tcb.js +6 -4
- package/lib/commands/run/create.js +6 -1
- package/lib/commands/run/delete.js +6 -1
- package/lib/commands/run/image/common.js +1 -1
- package/lib/commands/run/image/delete.js +5 -0
- package/lib/commands/run/image/download.js +5 -0
- package/lib/commands/run/image/list.js +5 -0
- package/lib/commands/run/image/upload.js +5 -0
- package/lib/commands/run/index.js +1 -0
- package/lib/commands/run/list.js +7 -1
- package/lib/commands/run/service/config.js +112 -0
- package/lib/commands/run/service/create.js +140 -0
- package/lib/commands/run/service/deploy.js +145 -0
- package/lib/commands/run/service/index.js +21 -0
- package/lib/commands/run/service/list.js +115 -0
- package/lib/commands/run/service/update.js +132 -0
- package/lib/commands/run/version/common.js +1 -1
- package/lib/commands/run/version/create.js +5 -0
- package/lib/commands/run/version/delete.js +5 -0
- package/lib/commands/run/version/list.js +5 -0
- package/lib/commands/run/version/modify.js +5 -0
- package/lib/commands/run/version/update.js +5 -0
- package/lib/constant.js +20 -1
- package/lib/help.js +40 -38
- package/lib/run/index.js +1 -0
- package/lib/run/service/common.js +163 -0
- package/lib/run/service/config.js +70 -0
- package/lib/run/service/create.js +67 -0
- package/lib/run/service/deployPackage.js +89 -0
- package/lib/run/service/index.js +23 -0
- package/lib/run/service/list.js +31 -0
- package/lib/run/service/showLogs.js +116 -0
- package/lib/run/service/update.js +83 -0
- package/lib/utils/checkTcbrEnv.js +74 -0
- package/lib/utils/commonParamsCheck.js +48 -0
- package/lib/utils/index.js +3 -0
- package/lib/utils/net/http-request.js +4 -4
- package/lib/utils/tcbrApi/callTcbrApi.js +38 -0
- package/lib/utils/tcbrApi/index.js +17 -0
- package/lib/utils/tcbrApi/tcbr-cloud-api/cloud-api-service.js +268 -0
- package/lib/utils/tcbrApi/tcbr-cloud-api/error.js +17 -0
- package/lib/utils/tcbrApi/tcbr-cloud-api/index.js +17 -0
- package/lib/utils/tcbrApi/tcbr-cloud-api/request.js +40 -0
- package/lib/utils/tcbrApi/tcbr-cloud-api-request.js +61 -0
- package/lib/utils/validator.js +32 -1
- package/package.json +88 -88
- package/src/commands/run/create.ts +9 -2
- package/src/commands/run/delete.ts +8 -2
- package/src/commands/run/image/common.ts +1 -1
- package/src/commands/run/image/delete.ts +8 -1
- package/src/commands/run/image/download.ts +7 -1
- package/src/commands/run/image/list.ts +7 -2
- package/src/commands/run/image/upload.ts +8 -1
- package/src/commands/run/index.ts +2 -1
- package/src/commands/run/list.ts +11 -3
- package/src/commands/run/service/config.ts +81 -0
- package/src/commands/run/service/create.ts +118 -0
- package/src/commands/run/service/deploy.ts +121 -0
- package/src/commands/run/service/index.ts +5 -0
- package/src/commands/run/service/list.ts +94 -0
- package/src/commands/run/service/update.ts +104 -0
- package/src/commands/run/version/common.ts +1 -1
- package/src/commands/run/version/create.ts +8 -1
- package/src/commands/run/version/delete.ts +8 -2
- package/src/commands/run/version/list.ts +7 -1
- package/src/commands/run/version/modify.ts +8 -1
- package/src/commands/run/version/update.ts +8 -1
- package/src/constant.ts +35 -1
- package/src/help.ts +50 -48
- package/src/run/index.ts +2 -1
- package/src/run/service/common.ts +206 -0
- package/src/run/service/config.ts +77 -0
- package/src/run/service/create.ts +52 -0
- package/src/run/service/deployPackage.ts +65 -0
- package/src/run/service/index.ts +7 -0
- package/src/run/service/list.ts +29 -0
- package/src/run/service/showLogs.ts +98 -0
- package/src/run/service/update.ts +81 -0
- package/src/types.ts +128 -2
- package/src/utils/checkTcbrEnv.ts +67 -0
- package/src/utils/commonParamsCheck.ts +65 -0
- package/src/utils/index.ts +5 -1
- package/src/utils/net/http-request.ts +1 -1
- package/src/utils/tcbrApi/callTcbrApi.ts +28 -0
- package/src/utils/tcbrApi/index.ts +1 -0
- package/src/utils/tcbrApi/tcbr-cloud-api/cloud-api-service.ts +363 -0
- package/src/utils/tcbrApi/tcbr-cloud-api/error.ts +30 -0
- package/src/utils/tcbrApi/tcbr-cloud-api/index.ts +1 -0
- package/src/utils/tcbrApi/tcbr-cloud-api/request.ts +28 -0
- package/src/utils/tcbrApi/tcbr-cloud-api-request.ts +66 -0
- package/src/utils/validator.ts +64 -32
- package/types/commands/run/index.d.ts +1 -0
- package/types/commands/run/service/config.d.ts +14 -0
- package/types/commands/run/service/create.d.ts +13 -0
- package/types/commands/run/service/deploy.d.ts +13 -0
- package/types/commands/run/service/index.d.ts +5 -0
- package/types/commands/run/service/list.d.ts +13 -0
- package/types/commands/run/service/update.d.ts +13 -0
- package/types/constant.d.ts +18 -0
- package/types/run/index.d.ts +1 -0
- package/types/run/service/common.d.ts +32 -0
- package/types/run/service/config.d.ts +23 -0
- package/types/run/service/create.d.ts +7 -0
- package/types/run/service/deployPackage.d.ts +11 -0
- package/types/run/service/index.d.ts +7 -0
- package/types/run/service/list.d.ts +2 -0
- package/types/run/service/showLogs.d.ts +2 -0
- package/types/run/service/update.d.ts +2 -0
- package/types/types.d.ts +116 -2
- package/types/utils/checkTcbrEnv.d.ts +3 -0
- package/types/utils/commonParamsCheck.d.ts +3 -0
- package/types/utils/index.d.ts +3 -0
- package/types/utils/tcbrApi/callTcbrApi.d.ts +1 -0
- package/types/utils/tcbrApi/index.d.ts +1 -0
- package/types/utils/tcbrApi/tcbr-cloud-api/cloud-api-service.d.ts +51 -0
- package/types/utils/tcbrApi/tcbr-cloud-api/error.d.ts +20 -0
- package/types/utils/tcbrApi/tcbr-cloud-api/index.d.ts +1 -0
- package/types/utils/tcbrApi/tcbr-cloud-api/request.d.ts +4 -0
- package/types/utils/tcbrApi/tcbr-cloud-api-request.d.ts +9 -0
- package/types/utils/validator.d.ts +4 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { CloudApiService, parseOptionalParams, parseInputParam } from '../../utils'
|
|
2
|
+
import { ITcbrServiceOptions, IDescribeWxCloudBaseRunReleaseOrder, ITcbrServiceRequiredOptions } from '../../types'
|
|
3
|
+
import { CloudBaseError } from '@cloudbase/toolbox'
|
|
4
|
+
import { packageDeploy } from './index'
|
|
5
|
+
import { listImage } from '..'
|
|
6
|
+
import { DEFAULT_CPU_MEM_SET } from '../../constant'
|
|
7
|
+
|
|
8
|
+
const tcbService = CloudApiService.getInstance('tcb')
|
|
9
|
+
|
|
10
|
+
export async function describeWxCloudBaseRunReleaseOrder(options: IDescribeWxCloudBaseRunReleaseOrder) {
|
|
11
|
+
const res = await tcbService.request('DescribeWxCloudBaseRunReleaseOrder', {
|
|
12
|
+
EnvId: options.envId,
|
|
13
|
+
ServerName: options.serviceName
|
|
14
|
+
})
|
|
15
|
+
return res
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const convertNumber = (item) => {
|
|
19
|
+
if (isNaN(Number(item))) {
|
|
20
|
+
throw new CloudBaseError(`${item} 必须为数字`)
|
|
21
|
+
}
|
|
22
|
+
return Number(item)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const extractPolicyDetails = (policyDetails: string) => {
|
|
26
|
+
return policyDetails.split('&').map(condition => {
|
|
27
|
+
let [type, threshold] = [condition.split('=')[0], Number(condition.split('=')[1])]
|
|
28
|
+
if (isNaN(threshold) || !['cpu', 'mem'].includes(type)) {
|
|
29
|
+
throw new CloudBaseError('请输入合法的缩扩容配置')
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
PolicyType: type,
|
|
33
|
+
PolicyThreshold: threshold
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const parseEnvParams = (envParams: string) => {
|
|
39
|
+
return envParams.split('&').reduce((acc, cur) => {
|
|
40
|
+
const [key, value] = cur.split('=')
|
|
41
|
+
acc[key] = value
|
|
42
|
+
return acc
|
|
43
|
+
}, {})
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @description 合并当前与已有的环境变量,当前传入的环境变量 key 去重并取位置靠后的,如与原有环境变量 key 相同,则替换
|
|
48
|
+
* @param curEnvParams 当前输入的环境变量
|
|
49
|
+
* @param preEnvParams 已有的环境变量
|
|
50
|
+
* @returns
|
|
51
|
+
*/
|
|
52
|
+
export const mergeEnvParams = (curEnvParams: string, preEnvParams: string) => {
|
|
53
|
+
const curEnv = parseEnvParams(curEnvParams)
|
|
54
|
+
const preEnv = preEnvParams ? JSON.parse(preEnvParams) : {}
|
|
55
|
+
const curEnvKeys = Object.keys(curEnv)
|
|
56
|
+
Object.entries(preEnv).forEach(([key, value]) => {
|
|
57
|
+
if (!curEnvKeys.includes(key)) {
|
|
58
|
+
curEnv[key] = value
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
return JSON.stringify(curEnv)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function checkRequiredParams(options: ITcbrServiceRequiredOptions) {
|
|
65
|
+
if (!options.envId) {
|
|
66
|
+
throw new CloudBaseError('必须使用 -e 或 --envId 指定环境ID')
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!options.serviceName) {
|
|
70
|
+
throw new CloudBaseError('必须使用 -s 或 --serviceName 指定服务名')
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!options.containerPort) {
|
|
74
|
+
throw new CloudBaseError('必须使用 --containerPort 指定监听端口号')
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (!options.isCreated && !options.path) {
|
|
78
|
+
throw new CloudBaseError('请使用 --path 指定代码根目录')
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (options.isCreated && !options.path && !options.library_image && !options.image) {
|
|
82
|
+
throw new CloudBaseError('请使用 --path 指定代码根目录或 --library_image 指定线上镜像 tag ')
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
*
|
|
88
|
+
* @param options 原始用户输入
|
|
89
|
+
* @param isCreated 服务是否已被创建(未创建的服务不能使用镜像 tag )
|
|
90
|
+
* @param defaultOverride 是否默认用上次的服务配置替代缺省值
|
|
91
|
+
* @param previousServerConfig 上次的服务配置
|
|
92
|
+
* @returns
|
|
93
|
+
*/
|
|
94
|
+
export async function tcbrServiceOptions(options: ITcbrServiceOptions, isCreated: boolean, defaultOverride?: boolean, previousServerConfig?) {
|
|
95
|
+
let {
|
|
96
|
+
noConfirm: _noConfirm = false,
|
|
97
|
+
override: _override = (defaultOverride || false),
|
|
98
|
+
envId,
|
|
99
|
+
serviceName,
|
|
100
|
+
path,
|
|
101
|
+
cpu,
|
|
102
|
+
mem,
|
|
103
|
+
minNum,
|
|
104
|
+
maxNum,
|
|
105
|
+
policyDetails,
|
|
106
|
+
customLogs,
|
|
107
|
+
envParams,
|
|
108
|
+
containerPort,
|
|
109
|
+
remark,
|
|
110
|
+
targetDir,
|
|
111
|
+
dockerfile,
|
|
112
|
+
image,
|
|
113
|
+
library_image,
|
|
114
|
+
json: _json = false
|
|
115
|
+
} = options
|
|
116
|
+
|
|
117
|
+
// 检查必选参数是否填写
|
|
118
|
+
checkRequiredParams({
|
|
119
|
+
envId,
|
|
120
|
+
serviceName,
|
|
121
|
+
containerPort,
|
|
122
|
+
isCreated,
|
|
123
|
+
path,
|
|
124
|
+
library_image,
|
|
125
|
+
image
|
|
126
|
+
})
|
|
127
|
+
containerPort = Number(containerPort)
|
|
128
|
+
|
|
129
|
+
// 处理用户输入的参数
|
|
130
|
+
const DeployInfo: any = {
|
|
131
|
+
DeployType: library_image || image
|
|
132
|
+
? 'image'
|
|
133
|
+
: 'package',
|
|
134
|
+
DeployRemark: remark || '',
|
|
135
|
+
}
|
|
136
|
+
// 可选参数进行校验和转换
|
|
137
|
+
let {
|
|
138
|
+
cpuConverted,
|
|
139
|
+
memConverted,
|
|
140
|
+
maxNumConverted,
|
|
141
|
+
minNumConverted
|
|
142
|
+
} = parseOptionalParams({
|
|
143
|
+
cpu,
|
|
144
|
+
mem,
|
|
145
|
+
maxNum,
|
|
146
|
+
minNum
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
const newServiceOptions = {
|
|
150
|
+
ServerName: serviceName,
|
|
151
|
+
EnvId: envId,
|
|
152
|
+
ServerConfig: {
|
|
153
|
+
EnvId: envId,
|
|
154
|
+
MaxNum: parseInputParam(maxNumConverted, _override, convertNumber, previousServerConfig?.MaxNum, 50),
|
|
155
|
+
MinNum: parseInputParam(minNumConverted, _override, convertNumber, previousServerConfig?.MinNum, 0),
|
|
156
|
+
BuildDir: parseInputParam(targetDir, _override, null, previousServerConfig?.BuildDir, '.'),
|
|
157
|
+
Cpu: parseInputParam(cpuConverted, _override, null, previousServerConfig?.Cpu, 0.5),
|
|
158
|
+
Mem: parseInputParam(memConverted, _override, null, previousServerConfig?.Mem, 1),
|
|
159
|
+
OpenAccessTypes: ['PUBLIC'],
|
|
160
|
+
ServerName: serviceName,
|
|
161
|
+
InitialDelaySeconds: 2,
|
|
162
|
+
CustomLogs: parseInputParam(customLogs, _override, null, previousServerConfig?.CustomLogs, 'stdout'),
|
|
163
|
+
CreateTime: previousServerConfig?.CreateTime || (new Date()).toLocaleString().replace(/\//g, '-'),
|
|
164
|
+
PolicyDetails: parseInputParam(policyDetails, _override, extractPolicyDetails, previousServerConfig?.PolicyDetails, DEFAULT_CPU_MEM_SET),
|
|
165
|
+
EnvParams: parseInputParam(envParams, _override, mergeEnvParams, previousServerConfig?.EnvParams, '', previousServerConfig?.EnvParams),
|
|
166
|
+
Port: containerPort,
|
|
167
|
+
HasDockerfile: true,
|
|
168
|
+
Dockerfile: dockerfile || 'Dockerfile',
|
|
169
|
+
},
|
|
170
|
+
DeployInfo: {
|
|
171
|
+
...DeployInfo
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (DeployInfo.DeployType === 'package') {
|
|
176
|
+
// 本地上传
|
|
177
|
+
const { PackageName, PackageVersion } = await packageDeploy({
|
|
178
|
+
envId,
|
|
179
|
+
serviceName,
|
|
180
|
+
filePath: path,
|
|
181
|
+
})
|
|
182
|
+
DeployInfo.PackageName = PackageName
|
|
183
|
+
DeployInfo.PackageVersion = PackageVersion
|
|
184
|
+
} else if (DeployInfo.DeployType === 'image') {
|
|
185
|
+
// 拉取镜像
|
|
186
|
+
const imageList = await listImage({
|
|
187
|
+
envId,
|
|
188
|
+
serviceName
|
|
189
|
+
})
|
|
190
|
+
if (library_image) {
|
|
191
|
+
const imageInfo = imageList.find(({ Tag }) => Tag === library_image)
|
|
192
|
+
if (!imageInfo) {
|
|
193
|
+
throw new CloudBaseError(`镜像 ${library_image} 不存在`)
|
|
194
|
+
}
|
|
195
|
+
DeployInfo.ImageUrl = imageInfo.ImageUrl
|
|
196
|
+
} else {
|
|
197
|
+
// 暂时不支持 image 镜像
|
|
198
|
+
throw new CloudBaseError('暂不支持 --image 参数,请使用 --library_image 指定线上镜像 tag')
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
newServiceOptions.DeployInfo = {
|
|
203
|
+
...DeployInfo
|
|
204
|
+
}
|
|
205
|
+
return newServiceOptions
|
|
206
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { describeCloudRunServerDetail } from './create'
|
|
2
|
+
import { ITcbrServiceConfigOptions, IDescribeCloudRunServerDetail } from '../../types'
|
|
3
|
+
import { CloudBaseError } from '@cloudbase/toolbox'
|
|
4
|
+
import { mergeEnvParams, extractPolicyDetails } from './common'
|
|
5
|
+
import { callTcbrApi, parseOptionalParams } from '../../utils'
|
|
6
|
+
|
|
7
|
+
export async function tcbrServiceConfigOptions(options: ITcbrServiceConfigOptions) {
|
|
8
|
+
let {
|
|
9
|
+
serviceName,
|
|
10
|
+
envId,
|
|
11
|
+
cpu,
|
|
12
|
+
mem,
|
|
13
|
+
minNum,
|
|
14
|
+
maxNum,
|
|
15
|
+
policyDetails,
|
|
16
|
+
customLogs,
|
|
17
|
+
envParams,
|
|
18
|
+
} = options
|
|
19
|
+
|
|
20
|
+
if (!envId) {
|
|
21
|
+
throw new CloudBaseError('必须使用 -e 或 --envId 指定环境ID')
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (!serviceName) {
|
|
25
|
+
throw new CloudBaseError('必须使用 -s 或 --serviceName 指定服务名')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let {
|
|
29
|
+
cpuConverted,
|
|
30
|
+
memConverted,
|
|
31
|
+
maxNumConverted,
|
|
32
|
+
minNumConverted
|
|
33
|
+
} = parseOptionalParams({
|
|
34
|
+
cpu,
|
|
35
|
+
mem,
|
|
36
|
+
maxNum,
|
|
37
|
+
minNum
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
const serviceInfo = await describeCloudRunServerDetail({
|
|
41
|
+
envId,
|
|
42
|
+
serviceName
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
if(serviceInfo instanceof Error && serviceInfo['code'] === 'InvalidParameter') {
|
|
46
|
+
throw new CloudBaseError('服务不存在,请检查服务名是否正确或用 tcb run service:create 创建服务')
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const { ServerConfig: previousServerConfig } = serviceInfo.data as IDescribeCloudRunServerDetail
|
|
50
|
+
|
|
51
|
+
const newServiceOptions = {
|
|
52
|
+
EnvId: envId,
|
|
53
|
+
ServerName: serviceName,
|
|
54
|
+
OpenAccessTypes: previousServerConfig.OpenAccessTypes,
|
|
55
|
+
Cpu: cpuConverted || previousServerConfig.Cpu,
|
|
56
|
+
Mem: memConverted || previousServerConfig.Mem,
|
|
57
|
+
MinNum: minNumConverted || previousServerConfig.MinNum,
|
|
58
|
+
MaxNum: maxNumConverted || previousServerConfig.MaxNum,
|
|
59
|
+
PolicyDetails: policyDetails ? extractPolicyDetails(policyDetails) : previousServerConfig.PolicyDetails,
|
|
60
|
+
CustomLogs: customLogs || previousServerConfig.CustomLogs,
|
|
61
|
+
EnvParams: envParams ? mergeEnvParams(envParams, previousServerConfig?.EnvParams) : previousServerConfig.EnvParams,
|
|
62
|
+
InitialDelaySeconds: 2,
|
|
63
|
+
CreateTime: previousServerConfig.CreateTime,
|
|
64
|
+
Port: previousServerConfig.Port,
|
|
65
|
+
HasDockerfile: true,
|
|
66
|
+
Dockerfile: previousServerConfig.Dockerfile,
|
|
67
|
+
BuildDir: previousServerConfig.BuildDir,
|
|
68
|
+
}
|
|
69
|
+
return newServiceOptions
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export async function updateCloudRunServerConfig(options) {
|
|
73
|
+
return await callTcbrApi('UpdateCloudRunServerConfig', {
|
|
74
|
+
EnvId: options.envId,
|
|
75
|
+
ServerBaseConfig: options.ServerBaseConfig,
|
|
76
|
+
})
|
|
77
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { callTcbrApi } from '../../utils'
|
|
2
|
+
import { getLogs, tcbrServiceOptions } from '.'
|
|
3
|
+
import inquirer from 'inquirer'
|
|
4
|
+
import { ITcbrServiceOptions } from '../../types'
|
|
5
|
+
import { logger } from '@cloudbase/toolbox'
|
|
6
|
+
|
|
7
|
+
export const describeCloudRunServerDetail = async (options: { envId: string; serviceName: string }) => {
|
|
8
|
+
return await callTcbrApi('DescribeCloudRunServerDetail', {
|
|
9
|
+
EnvId: options.envId,
|
|
10
|
+
ServerName: options.serviceName,
|
|
11
|
+
})
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function createCloudRunServer(serviceConfigOptions) {
|
|
15
|
+
return callTcbrApi('CreateCloudRunServer', serviceConfigOptions)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function createTcbrService(options: ITcbrServiceOptions) {
|
|
19
|
+
const newServiceOptions = await tcbrServiceOptions(options, false, false)
|
|
20
|
+
|
|
21
|
+
if (!options.noConfirm) {
|
|
22
|
+
const { confirm } = await inquirer.prompt([
|
|
23
|
+
{
|
|
24
|
+
type: 'confirm',
|
|
25
|
+
name: 'confirm',
|
|
26
|
+
message: '确定要创建服务吗?',
|
|
27
|
+
}
|
|
28
|
+
])
|
|
29
|
+
if (!confirm) {
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const createRes: any = await createCloudRunServer(newServiceOptions)
|
|
35
|
+
const taskId = createRes.data?.TaskId
|
|
36
|
+
|
|
37
|
+
if (options.json) {
|
|
38
|
+
console.log(JSON.stringify(createRes, null, 2))
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// `--verbose` 也用于全局指定参数,因此不能从 options 中获取到
|
|
42
|
+
if (process.argv.includes('--verbose')) {
|
|
43
|
+
await getLogs({
|
|
44
|
+
envId: options.envId,
|
|
45
|
+
taskId,
|
|
46
|
+
serviceName: options.serviceName
|
|
47
|
+
})
|
|
48
|
+
console.log(`本次任务的 TaskID: ${taskId}`)
|
|
49
|
+
} else {
|
|
50
|
+
logger.success('创建服务成功, 本次任务的 TaskID: ' + taskId)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import * as fs from 'fs'
|
|
3
|
+
import fetch from 'node-fetch'
|
|
4
|
+
import { createBuild } from '..'
|
|
5
|
+
import { CloudBaseError, execWithLoading, loadingFactory, zipDir } from '@cloudbase/toolbox'
|
|
6
|
+
|
|
7
|
+
interface IPackageDeploy {
|
|
8
|
+
envId: string,
|
|
9
|
+
serviceName: string,
|
|
10
|
+
filePath: string,
|
|
11
|
+
fileToIgnore?: string | string[]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function packageDeploy(options: IPackageDeploy) {
|
|
15
|
+
let {
|
|
16
|
+
envId,
|
|
17
|
+
serviceName,
|
|
18
|
+
filePath,
|
|
19
|
+
fileToIgnore
|
|
20
|
+
} = options
|
|
21
|
+
let { PackageName, PackageVersion, UploadUrl } = await createBuild({
|
|
22
|
+
envId,
|
|
23
|
+
serviceName
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
const loading = loadingFactory()
|
|
27
|
+
const zipFile = `.tcbr_${serviceName}_${Date.now()}.zip`
|
|
28
|
+
const dstPath = path.join(process.cwd(), zipFile)
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
if(fs.statSync(filePath).isDirectory()) {
|
|
32
|
+
loading.start('正在压缩文件…')
|
|
33
|
+
await zipDir(filePath, dstPath, fileToIgnore)
|
|
34
|
+
loading.succeed('压缩文件完成')
|
|
35
|
+
}
|
|
36
|
+
} catch (error) {
|
|
37
|
+
if(error.code === 'ENOENT') {
|
|
38
|
+
throw new CloudBaseError('找不到指定文件夹,请检查文件路径是否正确')
|
|
39
|
+
} else {
|
|
40
|
+
throw new CloudBaseError(error.message)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
return await execWithLoading(
|
|
46
|
+
async () => {
|
|
47
|
+
await fetch(UploadUrl, {
|
|
48
|
+
method: 'PUT',
|
|
49
|
+
body: fs.createReadStream(zipFile),
|
|
50
|
+
headers: {
|
|
51
|
+
'content-type': 'application/zip'
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
return { PackageName, PackageVersion }
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
startTip: '\n正在上传代码包...',
|
|
58
|
+
failTip: '上传代码包失败,请稍后重试'
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
} finally {
|
|
62
|
+
await fs.promises.unlink(dstPath)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { IServerInfo } from '../../types'
|
|
2
|
+
import { callTcbrApi, CloudApiService } from '../../utils'
|
|
3
|
+
|
|
4
|
+
const tcbService = CloudApiService.getInstance('tcb')
|
|
5
|
+
|
|
6
|
+
export const listService = async (options): Promise<IServerInfo[]> => {
|
|
7
|
+
// 没有 CreateTime 因此需要调用两个接口
|
|
8
|
+
const { data: { ServerList: serverList } } = await callTcbrApi('DescribeCloudRunServers', {
|
|
9
|
+
EnvId: options.envId,
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
const { CloudBaseRunServerSet: serverSet} = await tcbService.request('DescribeCloudBaseRunServers', {
|
|
13
|
+
EnvId: options.envId,
|
|
14
|
+
Offset: 0,
|
|
15
|
+
Limit: options.limit || 100
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
// 按照 ServerName 拼接结果
|
|
19
|
+
if(!serverList.length) return []
|
|
20
|
+
const serverInfo = serverList.map(serverItem => {
|
|
21
|
+
return {
|
|
22
|
+
...serverItem,
|
|
23
|
+
CreatedTime: serverSet.find( ( item ) => item.ServerName === serverItem.ServerName).CreatedTime
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
return serverInfo
|
|
28
|
+
|
|
29
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { callTcbrApi } from '../../utils'
|
|
2
|
+
import { EnumDeployStatus } from '../../constant'
|
|
3
|
+
import chalk from 'chalk'
|
|
4
|
+
|
|
5
|
+
export async function getBuildStatus(envId: string, serviceName: string) {
|
|
6
|
+
const { data: deployRes } = await callTcbrApi('DescribeCloudRunDeployRecord', {
|
|
7
|
+
EnvId: envId,
|
|
8
|
+
ServerName: serviceName,
|
|
9
|
+
})
|
|
10
|
+
if (deployRes?.DeployRecords) {
|
|
11
|
+
if (deployRes?.DeployRecords[0].Status === EnumDeployStatus.Deploying) {
|
|
12
|
+
return Promise.resolve('pending')
|
|
13
|
+
} else {
|
|
14
|
+
return Promise.resolve('completed')
|
|
15
|
+
}
|
|
16
|
+
} else {
|
|
17
|
+
return Promise.resolve('pending')
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
async function getBuildId(envId: string, serviceName: string): Promise<number> {
|
|
23
|
+
const { data: deployRes } = await callTcbrApi('DescribeCloudRunDeployRecord', {
|
|
24
|
+
EnvId: envId,
|
|
25
|
+
ServerName: serviceName,
|
|
26
|
+
})
|
|
27
|
+
if (deployRes?.DeployRecords) {
|
|
28
|
+
if (deployRes.DeployRecords[0].Status !== 'deploying') {
|
|
29
|
+
return Promise.resolve(deployRes.DeployRecords[0].BuildId)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function getRunId(envId: string, serviceName: string) {
|
|
35
|
+
return new Promise<string>((resolve) => {
|
|
36
|
+
const timer = setInterval(async () => {
|
|
37
|
+
const { data: deployRes } = await callTcbrApi('DescribeCloudRunDeployRecord', {
|
|
38
|
+
EnvId: envId,
|
|
39
|
+
ServerName: serviceName,
|
|
40
|
+
})
|
|
41
|
+
if (deployRes?.DeployRecords) {
|
|
42
|
+
clearInterval(timer)
|
|
43
|
+
resolve(deployRes.DeployRecords[0].RunId)
|
|
44
|
+
}
|
|
45
|
+
}, 3000)
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
// 多次获取 processLog
|
|
51
|
+
async function showProcessLogs(envId: string, runId: string, serviceName: string) {
|
|
52
|
+
return new Promise<void>(resolve => {
|
|
53
|
+
const timer = setInterval(async () => {
|
|
54
|
+
if (await getBuildStatus(envId, serviceName) === 'completed') {
|
|
55
|
+
clearInterval(timer)
|
|
56
|
+
resolve()
|
|
57
|
+
} else {
|
|
58
|
+
const { data: processLogs } = await callTcbrApi('DescribeCloudRunProcessLog', {
|
|
59
|
+
EnvId: envId,
|
|
60
|
+
RunId: runId,
|
|
61
|
+
})
|
|
62
|
+
if (processLogs?.Logs) {
|
|
63
|
+
console.log(processLogs?.Logs.join('\n'))
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}, 5000)
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// buildLog 仅在完成后获取一次(未完成 BuildId 为0)
|
|
71
|
+
async function showBuildLogs(envId: string, serviceName: string, serverVersion = '', offset = 0) {
|
|
72
|
+
const buildId = await getBuildId(envId, serviceName)
|
|
73
|
+
|
|
74
|
+
const { data } = await callTcbrApi('DescribeCloudRunBuildLog', {
|
|
75
|
+
EnvId: envId,
|
|
76
|
+
BuildId: buildId,
|
|
77
|
+
ServerName: serviceName,
|
|
78
|
+
ServerVersion: serverVersion || '',
|
|
79
|
+
Offset: offset || 0,
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
if (data?.Log?.Text) {
|
|
83
|
+
console.log(data?.Log?.Text)
|
|
84
|
+
}
|
|
85
|
+
return Promise.resolve()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export async function getLogs(options) {
|
|
89
|
+
|
|
90
|
+
const runId = await getRunId(options.envId, options.serviceName)
|
|
91
|
+
|
|
92
|
+
console.log(chalk.blue('============ 日志开始 ==============='))
|
|
93
|
+
await showProcessLogs(options.envId, runId, options.serviceName)
|
|
94
|
+
if (await getBuildStatus(options.envId, options.serviceName) === 'completed') {
|
|
95
|
+
await showBuildLogs(options.envId, options.serviceName)
|
|
96
|
+
}
|
|
97
|
+
console.log(chalk.blue('============ 日志结束 ==============='))
|
|
98
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { CloudBaseError, logger } from '@cloudbase/toolbox'
|
|
2
|
+
import inquirer from 'inquirer'
|
|
3
|
+
import { describeCloudRunServerDetail } from '..'
|
|
4
|
+
import { callTcbrApi } from '../../utils'
|
|
5
|
+
import { tcbrServiceOptions } from './common'
|
|
6
|
+
import { getBuildStatus, getLogs } from './showLogs'
|
|
7
|
+
|
|
8
|
+
export async function updateCloudRunServer(serviceConfigOptions) {
|
|
9
|
+
try {
|
|
10
|
+
const res = await callTcbrApi('UpdateCloudRunServer', serviceConfigOptions)
|
|
11
|
+
return res
|
|
12
|
+
} catch (error) {
|
|
13
|
+
console.log(error)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function updateTcbrService(options) {
|
|
18
|
+
const { data: serviceDetail } = await describeCloudRunServerDetail({
|
|
19
|
+
envId: options.envId,
|
|
20
|
+
serviceName: options.serviceName
|
|
21
|
+
})
|
|
22
|
+
if(serviceDetail === undefined) {
|
|
23
|
+
// 服务不存在
|
|
24
|
+
throw new CloudBaseError('当前服务不存在,请使用 tcb run service:create 创建服务')
|
|
25
|
+
}
|
|
26
|
+
// 查询是否存在发布单
|
|
27
|
+
/* const { IsExist: isExist } = await describeWxCloudBaseRunReleaseOrder({
|
|
28
|
+
envId: options.envId,
|
|
29
|
+
serviceName: options.serviceName
|
|
30
|
+
})
|
|
31
|
+
if(isExist) {
|
|
32
|
+
throw new CloudBaseError('服务正在更新部署,请稍后再试,或查看实时部署日志')
|
|
33
|
+
} */
|
|
34
|
+
const status = await getBuildStatus(options.envId, options.serviceName)
|
|
35
|
+
if(status === 'pending') {
|
|
36
|
+
throw new CloudBaseError('服务正在更新部署,请稍后再试,或查看实时部署日志')
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 获取上次的服务配置信息
|
|
40
|
+
const previousServerConfig = serviceDetail?.ServerConfig
|
|
41
|
+
|
|
42
|
+
const newServiceOptions = await tcbrServiceOptions(options, true, true, previousServerConfig)
|
|
43
|
+
|
|
44
|
+
// 二次确认
|
|
45
|
+
if(!options.noConfirm) {
|
|
46
|
+
const { confirm } = await inquirer.prompt([
|
|
47
|
+
{
|
|
48
|
+
type: 'confirm',
|
|
49
|
+
name: 'confirm',
|
|
50
|
+
message: '确定要更新服务吗?',
|
|
51
|
+
}
|
|
52
|
+
])
|
|
53
|
+
if(!confirm) {
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const updateRes: any = await updateCloudRunServer(newServiceOptions)
|
|
59
|
+
|
|
60
|
+
if(updateRes instanceof Error) {
|
|
61
|
+
// 当前有发布任务在运行中
|
|
62
|
+
throw new CloudBaseError('当前已有部署发布任务运行中,请稍后再试,或查看实时部署日志')
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const taskId = updateRes.data?.TaskId
|
|
66
|
+
|
|
67
|
+
if(options.json) {
|
|
68
|
+
console.log(JSON.stringify(updateRes, null, 2))
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if(process.argv.includes('--verbose')) {
|
|
72
|
+
await getLogs({
|
|
73
|
+
envId: options.envId,
|
|
74
|
+
taskId,
|
|
75
|
+
serviceName: options.serviceName
|
|
76
|
+
})
|
|
77
|
+
console.log(`本次任务的 TaskID: ${taskId}`)
|
|
78
|
+
} else {
|
|
79
|
+
logger.success('更新服务成功, 本次任务的 TaskID: ' + taskId)
|
|
80
|
+
}
|
|
81
|
+
}
|