@geek-fun/serverlessinsight 0.6.14 → 0.7.0

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.
Files changed (45) hide show
  1. package/AGENTS.md +405 -10
  2. package/README.md +1 -0
  3. package/dist/package.json +8 -2
  4. package/dist/src/commands/deploy.js +4 -0
  5. package/dist/src/commands/destroy.js +4 -0
  6. package/dist/src/common/credentials.js +12 -0
  7. package/dist/src/common/providerEnum.js +1 -0
  8. package/dist/src/common/runtimeMapper.js +24 -3
  9. package/dist/src/common/volcengineClient/apigwOperations.js +271 -0
  10. package/dist/src/common/volcengineClient/iamOperations.js +349 -0
  11. package/dist/src/common/volcengineClient/index.js +99 -0
  12. package/dist/src/common/volcengineClient/tlsOperations.js +256 -0
  13. package/dist/src/common/volcengineClient/tosOperations.js +440 -0
  14. package/dist/src/common/volcengineClient/types.js +26 -0
  15. package/dist/src/common/volcengineClient/vefaasOperations.js +386 -0
  16. package/dist/src/lang/en.js +120 -0
  17. package/dist/src/lang/zh-CN.js +119 -0
  18. package/dist/src/stack/aliyunStack/fc3Resource.js +18 -3
  19. package/dist/src/stack/deploy.js +4 -0
  20. package/dist/src/stack/volcengineStack/apigwExecutor.js +87 -0
  21. package/dist/src/stack/volcengineStack/apigwPlanner.js +110 -0
  22. package/dist/src/stack/volcengineStack/apigwResource.js +302 -0
  23. package/dist/src/stack/volcengineStack/apigwTypes.js +106 -0
  24. package/dist/src/stack/volcengineStack/deployer.js +59 -0
  25. package/dist/src/stack/volcengineStack/destroyer.js +72 -0
  26. package/dist/src/stack/volcengineStack/index.js +44 -0
  27. package/dist/src/stack/volcengineStack/planner.js +27 -0
  28. package/dist/src/stack/volcengineStack/tosExecutor.js +106 -0
  29. package/dist/src/stack/volcengineStack/tosPlanner.js +96 -0
  30. package/dist/src/stack/volcengineStack/tosResource.js +103 -0
  31. package/dist/src/stack/volcengineStack/tosTypes.js +65 -0
  32. package/dist/src/stack/volcengineStack/vefaasExecutor.js +102 -0
  33. package/dist/src/stack/volcengineStack/vefaasPlanner.js +84 -0
  34. package/dist/src/stack/volcengineStack/vefaasResource.js +513 -0
  35. package/dist/src/stack/volcengineStack/vefaasTypes.js +75 -0
  36. package/dist/src/types/domains/state.js +3 -0
  37. package/dist/src/validator/functionSchema.js +13 -0
  38. package/dist/src/validator/rootSchema.js +1 -1
  39. package/dist/tsconfig.tsbuildinfo +1 -1
  40. package/package.json +8 -2
  41. package/samples/volcengine-poc-advanced.yml +59 -0
  42. package/samples/volcengine-poc-api.yml +31 -0
  43. package/samples/volcengine-poc-bucket.yml +17 -0
  44. package/samples/volcengine-poc-function.yml +19 -0
  45. package/samples/volcengine-poc-vpc.yml +34 -0
@@ -0,0 +1,271 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createApigwOperations = void 0;
4
+ const logger_1 = require("../logger");
5
+ const lang_1 = require("../../lang");
6
+ const createApigwOperations = (client) => {
7
+ if (!client) {
8
+ return {
9
+ createGateway: async (_config) => {
10
+ throw new Error(lang_1.lang.__('VOLCENGINE_APIGW_CLIENT_NOT_INITIALIZED'));
11
+ },
12
+ getGateway: async (_gatewayId) => {
13
+ throw new Error(lang_1.lang.__('VOLCENGINE_APIGW_CLIENT_NOT_INITIALIZED'));
14
+ },
15
+ findGatewayByName: async (_gatewayName) => {
16
+ throw new Error(lang_1.lang.__('VOLCENGINE_APIGW_CLIENT_NOT_INITIALIZED'));
17
+ },
18
+ updateGateway: async (_gatewayId, _config) => {
19
+ throw new Error(lang_1.lang.__('VOLCENGINE_APIGW_CLIENT_NOT_INITIALIZED'));
20
+ },
21
+ deleteGateway: async (_gatewayId) => {
22
+ throw new Error(lang_1.lang.__('VOLCENGINE_APIGW_CLIENT_NOT_INITIALIZED'));
23
+ },
24
+ createApi: async (_config) => {
25
+ throw new Error(lang_1.lang.__('VOLCENGINE_APIGW_CLIENT_NOT_INITIALIZED'));
26
+ },
27
+ getApi: async (_gatewayId, _apiId) => {
28
+ throw new Error(lang_1.lang.__('VOLCENGINE_APIGW_CLIENT_NOT_INITIALIZED'));
29
+ },
30
+ updateApi: async (_apiId, _config) => {
31
+ throw new Error(lang_1.lang.__('VOLCENGINE_APIGW_CLIENT_NOT_INITIALIZED'));
32
+ },
33
+ deleteApi: async (_gatewayId, _apiId) => {
34
+ throw new Error(lang_1.lang.__('VOLCENGINE_APIGW_CLIENT_NOT_INITIALIZED'));
35
+ },
36
+ deployApi: async (_gatewayId, _apiId) => {
37
+ throw new Error(lang_1.lang.__('VOLCENGINE_APIGW_CLIENT_NOT_INITIALIZED'));
38
+ },
39
+ bindDomain: async (_config) => {
40
+ throw new Error(lang_1.lang.__('VOLCENGINE_APIGW_CLIENT_NOT_INITIALIZED'));
41
+ },
42
+ unbindDomain: async (_gatewayId, _domainName) => {
43
+ throw new Error(lang_1.lang.__('VOLCENGINE_APIGW_CLIENT_NOT_INITIALIZED'));
44
+ },
45
+ };
46
+ }
47
+ return {
48
+ createGateway: async (config) => {
49
+ logger_1.logger.info(lang_1.lang.__('VOLCENGINE_CREATING_APIGW', { gatewayName: config.groupName }));
50
+ const params = {
51
+ Name: config.groupName,
52
+ ...(config.description && { Description: config.description }),
53
+ ...(config.protocol && { Protocol: config.protocol }),
54
+ };
55
+ const response = await client.fetchOpenAPI({
56
+ Action: 'CreateGateway',
57
+ Version: '2021-03-03',
58
+ method: 'POST',
59
+ headers: { 'content-type': 'application/json' },
60
+ data: params,
61
+ });
62
+ const data = (response.Result || {});
63
+ return {
64
+ gatewayId: data.GatewayId,
65
+ gatewayName: data.Name,
66
+ protocol: data.Protocol,
67
+ status: data.Status,
68
+ createdTime: data.CreatedTime,
69
+ description: data.Description,
70
+ subDomain: data.SubDomain,
71
+ };
72
+ },
73
+ getGateway: async (gatewayId) => {
74
+ try {
75
+ const response = await client.fetchOpenAPI({
76
+ Action: 'GetGateway',
77
+ Version: '2021-03-03',
78
+ method: 'POST',
79
+ headers: { 'content-type': 'application/json' },
80
+ data: { GatewayId: gatewayId },
81
+ });
82
+ const data = (response.Result || {});
83
+ return {
84
+ gatewayId: data.GatewayId,
85
+ gatewayName: data.Name,
86
+ protocol: data.Protocol,
87
+ status: data.Status,
88
+ createdTime: data.CreatedTime,
89
+ description: data.Description,
90
+ subDomain: data.SubDomain,
91
+ };
92
+ }
93
+ catch (error) {
94
+ if (error && typeof error === 'object' && 'code' in error) {
95
+ if (error.code === 'ResourceNotFound' || error.code === 'GatewayNotFound') {
96
+ return null;
97
+ }
98
+ }
99
+ throw error;
100
+ }
101
+ },
102
+ findGatewayByName: async (gatewayName) => {
103
+ const response = await client.fetchOpenAPI({
104
+ Action: 'ListGateways',
105
+ Version: '2021-03-03',
106
+ method: 'POST',
107
+ headers: { 'content-type': 'application/json' },
108
+ data: { Name: gatewayName },
109
+ });
110
+ const result = (response.Result || {});
111
+ const gateways = (result.Gateways || []);
112
+ const gateway = gateways.find((g) => g.Name === gatewayName);
113
+ if (!gateway)
114
+ return null;
115
+ return {
116
+ gatewayId: gateway.GatewayId,
117
+ gatewayName: gateway.Name,
118
+ protocol: gateway.Protocol,
119
+ status: gateway.Status,
120
+ createdTime: gateway.CreatedTime,
121
+ description: gateway.Description,
122
+ subDomain: gateway.SubDomain,
123
+ };
124
+ },
125
+ updateGateway: async (gatewayId, config) => {
126
+ const params = {
127
+ GatewayId: gatewayId,
128
+ Name: config.groupName,
129
+ ...(config.description && { Description: config.description }),
130
+ ...(config.protocol && { Protocol: config.protocol }),
131
+ };
132
+ await client.fetchOpenAPI({
133
+ Action: 'UpdateGateway',
134
+ Version: '2021-03-03',
135
+ method: 'POST',
136
+ headers: { 'content-type': 'application/json' },
137
+ data: params,
138
+ });
139
+ },
140
+ deleteGateway: async (gatewayId) => {
141
+ logger_1.logger.info(lang_1.lang.__('VOLCENGINE_DELETING_APIGW', { gatewayName: gatewayId }));
142
+ await client.fetchOpenAPI({
143
+ Action: 'DeleteGateway',
144
+ Version: '2021-03-03',
145
+ method: 'POST',
146
+ headers: { 'content-type': 'application/json' },
147
+ data: { GatewayId: gatewayId },
148
+ });
149
+ },
150
+ createApi: async (config) => {
151
+ const params = {
152
+ GatewayId: config.gatewayId,
153
+ Name: config.apiName,
154
+ Method: config.method,
155
+ Path: config.path,
156
+ BackendType: 'Function',
157
+ BackendConfig: {
158
+ FunctionName: config.backendFunctionName,
159
+ Timeout: config.requestTimeout ?? 60,
160
+ },
161
+ };
162
+ const response = await client.fetchOpenAPI({
163
+ Action: 'CreateApi',
164
+ Version: '2021-03-03',
165
+ method: 'POST',
166
+ headers: { 'content-type': 'application/json' },
167
+ data: params,
168
+ });
169
+ const data = (response.Result || {});
170
+ return data.ApiId;
171
+ },
172
+ getApi: async (gatewayId, apiId) => {
173
+ try {
174
+ const response = await client.fetchOpenAPI({
175
+ Action: 'GetApi',
176
+ Version: '2021-03-03',
177
+ method: 'POST',
178
+ headers: { 'content-type': 'application/json' },
179
+ data: { GatewayId: gatewayId, ApiId: apiId },
180
+ });
181
+ const data = (response.Result || {});
182
+ const backendConfig = (data.BackendConfig || {});
183
+ return {
184
+ apiId: data.ApiId,
185
+ apiName: data.Name,
186
+ gatewayId: data.GatewayId,
187
+ method: data.Method,
188
+ path: data.Path,
189
+ description: data.Description,
190
+ backendType: data.BackendType,
191
+ backendId: data.BackendId,
192
+ backendFunctionName: backendConfig.FunctionName,
193
+ status: data.Status,
194
+ createdTime: data.CreatedTime,
195
+ };
196
+ }
197
+ catch (error) {
198
+ if (error && typeof error === 'object' && 'code' in error) {
199
+ if (error.code === 'ResourceNotFound' || error.code === 'ApiNotFound') {
200
+ return null;
201
+ }
202
+ }
203
+ throw error;
204
+ }
205
+ },
206
+ updateApi: async (apiId, config) => {
207
+ const params = {
208
+ ApiId: apiId,
209
+ GatewayId: config.gatewayId,
210
+ Name: config.apiName,
211
+ Method: config.method,
212
+ Path: config.path,
213
+ BackendType: 'Function',
214
+ BackendConfig: {
215
+ FunctionName: config.backendFunctionName,
216
+ Timeout: config.requestTimeout ?? 60,
217
+ },
218
+ };
219
+ await client.fetchOpenAPI({
220
+ Action: 'UpdateApi',
221
+ Version: '2021-03-03',
222
+ method: 'POST',
223
+ headers: { 'content-type': 'application/json' },
224
+ data: params,
225
+ });
226
+ },
227
+ deleteApi: async (gatewayId, apiId) => {
228
+ await client.fetchOpenAPI({
229
+ Action: 'DeleteApi',
230
+ Version: '2021-03-03',
231
+ method: 'POST',
232
+ headers: { 'content-type': 'application/json' },
233
+ data: { GatewayId: gatewayId, ApiId: apiId },
234
+ });
235
+ },
236
+ deployApi: async (gatewayId, apiId) => {
237
+ await client.fetchOpenAPI({
238
+ Action: 'DeployApi',
239
+ Version: '2021-03-03',
240
+ method: 'POST',
241
+ headers: { 'content-type': 'application/json' },
242
+ data: { GatewayId: gatewayId, ApiId: apiId, Stage: 'RELEASE' },
243
+ });
244
+ },
245
+ bindDomain: async (config) => {
246
+ const params = {
247
+ GatewayId: config.gatewayId,
248
+ DomainName: config.domainName,
249
+ ...(config.certificateId && { CertificateId: config.certificateId }),
250
+ };
251
+ await client.fetchOpenAPI({
252
+ Action: 'BindDomain',
253
+ Version: '2021-03-03',
254
+ method: 'POST',
255
+ headers: { 'content-type': 'application/json' },
256
+ data: params,
257
+ });
258
+ logger_1.logger.info(lang_1.lang.__('APIGW_DOMAIN_BOUND_SUCCESS', { domain: config.domainName }));
259
+ },
260
+ unbindDomain: async (gatewayId, domainName) => {
261
+ await client.fetchOpenAPI({
262
+ Action: 'UnbindDomain',
263
+ Version: '2021-03-03',
264
+ method: 'POST',
265
+ headers: { 'content-type': 'application/json' },
266
+ data: { GatewayId: gatewayId, DomainName: domainName },
267
+ });
268
+ },
269
+ };
270
+ };
271
+ exports.createApigwOperations = createApigwOperations;
@@ -0,0 +1,349 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createIamOperations = void 0;
4
+ const logger_1 = require("../logger");
5
+ const lang_1 = require("../../lang");
6
+ const DEFAULT_TRUST_POLICY_SERVICES = ['vefaas.volcengine.com'];
7
+ const buildTrustPolicyDocument = (trustedServices) => {
8
+ return JSON.stringify({
9
+ Statement: [
10
+ {
11
+ Effect: 'Allow',
12
+ Action: ['sts:AssumeRole'],
13
+ Principal: {
14
+ Service: trustedServices,
15
+ },
16
+ },
17
+ ],
18
+ });
19
+ };
20
+ const VEFAAS_EXECUTION_POLICY = JSON.stringify({
21
+ Statement: [
22
+ {
23
+ Effect: 'Allow',
24
+ Action: ['vefaas:*'],
25
+ Resource: '*',
26
+ },
27
+ {
28
+ Effect: 'Allow',
29
+ Action: ['tos:GetObject', 'tos:PutObject', 'tos:DeleteObject', 'tos:ListBucket'],
30
+ Resource: '*',
31
+ },
32
+ {
33
+ Effect: 'Allow',
34
+ Action: ['vpc:DescribeVpcs', 'vpc:DescribeSubnets', 'vpc:DescribeSecurityGroups'],
35
+ Resource: '*',
36
+ },
37
+ {
38
+ Effect: 'Allow',
39
+ Action: ['tls:CreateProject', 'tls:CreateTopic', 'tls:PutLogs'],
40
+ Resource: '*',
41
+ },
42
+ ],
43
+ });
44
+ const createIamOperations = (iamClient) => {
45
+ const createAndAttachPolicy = async (roleName) => {
46
+ const policyName = `${roleName}-policy`;
47
+ try {
48
+ await iamClient.fetchOpenAPI({
49
+ Action: 'CreatePolicy',
50
+ Version: '2024-01-01',
51
+ method: 'POST',
52
+ headers: { 'content-type': 'application/json' },
53
+ data: {
54
+ PolicyName: policyName,
55
+ PolicyDocument: VEFAAS_EXECUTION_POLICY,
56
+ Description: `veFaaS execution policy for ${roleName}`,
57
+ },
58
+ });
59
+ }
60
+ catch (error) {
61
+ if (error && typeof error === 'object' && 'code' in error) {
62
+ if (error.code === 'PolicyAlreadyExists' || error.code === 'Conflict') {
63
+ logger_1.logger.info(lang_1.lang.__('IAM_POLICY_ALREADY_EXISTS', { policyName }));
64
+ }
65
+ else {
66
+ throw error;
67
+ }
68
+ }
69
+ else {
70
+ throw error;
71
+ }
72
+ }
73
+ try {
74
+ await iamClient.fetchOpenAPI({
75
+ Action: 'AttachRolePolicy',
76
+ Version: '2024-01-01',
77
+ method: 'POST',
78
+ headers: { 'content-type': 'application/json' },
79
+ data: {
80
+ RoleName: roleName,
81
+ PolicyName: policyName,
82
+ PolicyType: 'Custom',
83
+ },
84
+ });
85
+ }
86
+ catch (error) {
87
+ if (error && typeof error === 'object' && 'code' in error) {
88
+ if (error.code === 'PolicyAlreadyAttached' || error.code === 'Conflict') {
89
+ logger_1.logger.info(lang_1.lang.__('IAM_POLICY_ALREADY_ATTACHED', { policyName, roleName }));
90
+ }
91
+ else {
92
+ throw error;
93
+ }
94
+ }
95
+ else {
96
+ throw error;
97
+ }
98
+ }
99
+ return policyName;
100
+ };
101
+ const detachAndDeletePolicy = async (roleName) => {
102
+ const policyName = `${roleName}-policy`;
103
+ try {
104
+ await iamClient.fetchOpenAPI({
105
+ Action: 'DetachRolePolicy',
106
+ Version: '2024-01-01',
107
+ method: 'POST',
108
+ headers: { 'content-type': 'application/json' },
109
+ data: {
110
+ RoleName: roleName,
111
+ PolicyName: policyName,
112
+ PolicyType: 'Custom',
113
+ },
114
+ });
115
+ }
116
+ catch {
117
+ // Ignore if policy is not attached
118
+ }
119
+ try {
120
+ await iamClient.fetchOpenAPI({
121
+ Action: 'DeletePolicy',
122
+ Version: '2024-01-01',
123
+ method: 'POST',
124
+ headers: { 'content-type': 'application/json' },
125
+ data: {
126
+ PolicyName: policyName,
127
+ PolicyType: 'Custom',
128
+ },
129
+ });
130
+ }
131
+ catch {
132
+ // Ignore if policy doesn't exist
133
+ }
134
+ };
135
+ return {
136
+ createRole: async (config) => {
137
+ const roleName = config.roleName;
138
+ const trustedServices = config.trustPolicy.Statement[0]?.Principal.Service || DEFAULT_TRUST_POLICY_SERVICES;
139
+ const trustPolicyDocument = buildTrustPolicyDocument(trustedServices);
140
+ try {
141
+ const response = await iamClient.fetchOpenAPI({
142
+ Action: 'CreateRole',
143
+ Version: '2024-01-01',
144
+ method: 'POST',
145
+ headers: { 'content-type': 'application/json' },
146
+ data: {
147
+ RoleName: roleName,
148
+ TrustPolicyDocument: trustPolicyDocument,
149
+ DisplayName: config.displayName,
150
+ Description: config.description ?? `ServerlessInsight veFaaS execution role for ${roleName}`,
151
+ MaxSessionDuration: config.maxSessionDuration ?? 3600,
152
+ },
153
+ });
154
+ const data = (response.Result || {});
155
+ const roleData = (data.Role || {});
156
+ const policyName = await createAndAttachPolicy(roleName);
157
+ logger_1.logger.info(lang_1.lang.__('IAM_ROLE_CREATED', { roleName }));
158
+ return {
159
+ roleName: roleData.RoleName,
160
+ roleId: roleData.RoleId,
161
+ trn: roleData.TRN,
162
+ description: roleData.Description,
163
+ createdTime: roleData.CreateTime,
164
+ maxSessionDuration: roleData.MaxSessionDuration,
165
+ trustPolicyDocument,
166
+ policyName,
167
+ };
168
+ }
169
+ catch (error) {
170
+ if (error && typeof error === 'object' && 'code' in error) {
171
+ if (error.code === 'RoleAlreadyExists' || error.code === 'Conflict') {
172
+ logger_1.logger.info(lang_1.lang.__('IAM_ROLE_ALREADY_EXISTS', { roleName }));
173
+ try {
174
+ const existingRole = await iamClient.fetchOpenAPI({
175
+ Action: 'GetRole',
176
+ Version: '2024-01-01',
177
+ method: 'POST',
178
+ headers: { 'content-type': 'application/json' },
179
+ data: { RoleName: roleName },
180
+ });
181
+ await iamClient.fetchOpenAPI({
182
+ Action: 'UpdateTrustPolicy',
183
+ Version: '2024-01-01',
184
+ method: 'POST',
185
+ headers: { 'content-type': 'application/json' },
186
+ data: {
187
+ RoleName: roleName,
188
+ TrustPolicyDocument: trustPolicyDocument,
189
+ },
190
+ });
191
+ const policyName = await createAndAttachPolicy(roleName);
192
+ const roleData = (existingRole.Result || {})
193
+ .Role;
194
+ return {
195
+ roleName: roleData?.RoleName,
196
+ roleId: roleData?.RoleId,
197
+ trn: roleData?.TRN,
198
+ description: roleData?.Description,
199
+ createdTime: roleData?.CreateTime,
200
+ maxSessionDuration: roleData?.MaxSessionDuration,
201
+ trustPolicyDocument,
202
+ policyName,
203
+ };
204
+ }
205
+ catch (recoveryError) {
206
+ // eslint-disable-next-line preserve-caught-error
207
+ throw new Error(lang_1.lang.__('IAM_ROLE_DRIFT_RECOVERY_FAILED', {
208
+ roleName,
209
+ error: recoveryError instanceof Error ? recoveryError.message : String(recoveryError),
210
+ }));
211
+ }
212
+ }
213
+ }
214
+ throw error;
215
+ }
216
+ },
217
+ getRole: async (roleName) => {
218
+ try {
219
+ const response = await iamClient.fetchOpenAPI({
220
+ Action: 'GetRole',
221
+ Version: '2024-01-01',
222
+ method: 'POST',
223
+ headers: { 'content-type': 'application/json' },
224
+ data: { RoleName: roleName },
225
+ });
226
+ const roleData = (response.Result || {}).Role;
227
+ if (!roleData) {
228
+ return null;
229
+ }
230
+ return {
231
+ roleName: roleData.RoleName,
232
+ roleId: roleData.RoleId,
233
+ trn: roleData.TRN,
234
+ description: roleData.Description,
235
+ createdTime: roleData.CreateTime,
236
+ maxSessionDuration: roleData.MaxSessionDuration,
237
+ trustPolicyDocument: roleData.TrustPolicyDocument,
238
+ policyName: `${roleName}-policy`,
239
+ };
240
+ }
241
+ catch (error) {
242
+ if (error && typeof error === 'object' && 'code' in error) {
243
+ if (error.code === 'RoleNotFound' || error.code === 'NoSuchEntity') {
244
+ return null;
245
+ }
246
+ }
247
+ throw error;
248
+ }
249
+ },
250
+ updateRoleTrustPolicy: async (roleName, trustPolicy) => {
251
+ const trustPolicyDocument = JSON.stringify(trustPolicy);
252
+ try {
253
+ await iamClient.fetchOpenAPI({
254
+ Action: 'UpdateTrustPolicy',
255
+ Version: '2024-01-01',
256
+ method: 'POST',
257
+ headers: { 'content-type': 'application/json' },
258
+ data: {
259
+ RoleName: roleName,
260
+ TrustPolicyDocument: trustPolicyDocument,
261
+ },
262
+ });
263
+ logger_1.logger.info(lang_1.lang.__('IAM_ROLE_TRUST_POLICY_UPDATED', { roleName }));
264
+ }
265
+ catch (error) {
266
+ if (error && typeof error === 'object' && 'code' in error) {
267
+ if (error.code === 'RoleNotFound' || error.code === 'NoSuchEntity') {
268
+ // eslint-disable-next-line preserve-caught-error
269
+ throw new Error(lang_1.lang.__('IAM_ROLE_NOT_FOUND_IN_CLOUD', { roleName }));
270
+ }
271
+ }
272
+ throw error;
273
+ }
274
+ },
275
+ deleteRole: async (roleName) => {
276
+ await detachAndDeletePolicy(roleName);
277
+ try {
278
+ await iamClient.fetchOpenAPI({
279
+ Action: 'DeleteRole',
280
+ Version: '2024-01-01',
281
+ method: 'POST',
282
+ headers: { 'content-type': 'application/json' },
283
+ data: { RoleName: roleName },
284
+ });
285
+ logger_1.logger.info(lang_1.lang.__('IAM_ROLE_DELETED', { roleName }));
286
+ }
287
+ catch (error) {
288
+ if (error && typeof error === 'object' && 'code' in error) {
289
+ if (error.code === 'RoleNotFound' || error.code === 'NoSuchEntity') {
290
+ logger_1.logger.warn(lang_1.lang.__('IAM_ROLE_NOT_FOUND_IN_CLOUD', { roleName }));
291
+ return;
292
+ }
293
+ }
294
+ throw error;
295
+ }
296
+ },
297
+ attachRolePolicy: async (roleName, policyName, policyType) => {
298
+ try {
299
+ await iamClient.fetchOpenAPI({
300
+ Action: 'AttachRolePolicy',
301
+ Version: '2024-01-01',
302
+ method: 'POST',
303
+ headers: { 'content-type': 'application/json' },
304
+ data: {
305
+ RoleName: roleName,
306
+ PolicyName: policyName,
307
+ PolicyType: policyType,
308
+ },
309
+ });
310
+ logger_1.logger.info(lang_1.lang.__('IAM_POLICY_ATTACHED', { policyName, roleName }));
311
+ }
312
+ catch (error) {
313
+ if (error && typeof error === 'object' && 'code' in error) {
314
+ if (error.code === 'PolicyAlreadyAttached' || error.code === 'Conflict') {
315
+ logger_1.logger.info(lang_1.lang.__('IAM_POLICY_ALREADY_ATTACHED', { policyName, roleName }));
316
+ return;
317
+ }
318
+ }
319
+ throw error;
320
+ }
321
+ },
322
+ detachRolePolicy: async (roleName, policyName) => {
323
+ try {
324
+ await iamClient.fetchOpenAPI({
325
+ Action: 'DetachRolePolicy',
326
+ Version: '2024-01-01',
327
+ method: 'POST',
328
+ headers: { 'content-type': 'application/json' },
329
+ data: {
330
+ RoleName: roleName,
331
+ PolicyName: policyName,
332
+ PolicyType: 'Custom',
333
+ },
334
+ });
335
+ logger_1.logger.info(lang_1.lang.__('IAM_POLICY_DETACHED', { policyName, roleName }));
336
+ }
337
+ catch (error) {
338
+ if (error &&
339
+ typeof error === 'object' &&
340
+ 'code' in error &&
341
+ (error.code === 'PolicyNotAttached' || error.code === 'NoSuchEntity')) {
342
+ return;
343
+ }
344
+ logger_1.logger.warn(lang_1.lang.__('IAM_POLICY_DETACH_FAILED', { policyName, roleName, error: String(error) }));
345
+ }
346
+ },
347
+ };
348
+ };
349
+ exports.createIamOperations = createIamOperations;