UNPKG

5.76 kBJavaScriptView Raw
1'use strict';
2
3const Ram = require('@alicloud/ram');
4const getProfile = require('./profile').getProfile;
5const promiseRetry = require('./retry');
6const { red } = require('colors');
7const debug = require('debug')('fun:ram');
8const _ = require('lodash');
9const { throwProcessedPopPermissionError } = require('./error-message');
10
11const FNF_ASSUME_ROLE_POLICY = {
12 'Statement': [
13 {
14 'Action': 'sts:AssumeRole',
15 'Effect': 'Allow',
16 'Principal': {
17 'Service': [
18 'fnf.aliyuncs.com'
19 ]
20 }
21 }
22 ],
23 'Version': '1'
24};
25
26const getRamClient = async () => {
27 const profile = await getProfile();
28
29 const ram = new Ram({
30 accessKeyId: profile.accessKeyId,
31 accessKeySecret: profile.accessKeySecret,
32 endpoint: 'https://ram.aliyuncs.com',
33 opts: {
34 timeout: profile.timeout * 1000
35 }
36 });
37
38 const realRequest = ram.request.bind(ram);
39 ram.request = async (action, params, options) => {
40 try {
41 return await realRequest(action, params, options);
42 } catch (ex) {
43 await throwProcessedPopPermissionError(ex, action);
44 throw ex;
45 }
46 };
47 return ram;
48};
49
50function normalizeRoleOrPoliceName(roleName) {
51 return roleName.replace(/_/g, '-');
52}
53
54async function deletePolicyNotDefaultVersion(ram, policyName) {
55 const listResponse = await ram.listPolicyVersions({
56 PolicyType: 'Custom',
57 PolicyName: policyName
58 });
59
60 const versions = (listResponse.PolicyVersions || {}).PolicyVersion;
61 if (versions) {
62 for (let version of versions) {
63 if (version.IsDefaultVersion === false) {
64 await ram.deletePolicyVersion({
65 PolicyName: policyName,
66 VersionId: version.VersionId
67 });
68 }
69 }
70 }
71}
72
73async function makePolicy(policyName, policyDocument) {
74 const ram = await getRamClient();
75
76 let exists = true;
77
78 await promiseRetry(async (retry, times) => {
79 try {
80 try {
81 await ram.getPolicy({
82 PolicyType: 'Custom',
83 PolicyName: policyName
84 });
85 } catch (ex) {
86 if (ex.code !== 'EntityNotExist.Policy') {
87 throw ex;
88 } else { exists = false; }
89 }
90
91 if (!exists) {
92 await ram.createPolicy({
93 PolicyName: policyName,
94 Description: 'generated by fc fun',
95 PolicyDocument: JSON.stringify(policyDocument)
96 });
97 } else {
98 // avoid limitExceeded.Policy.Version
99 await deletePolicyNotDefaultVersion(ram, policyName);
100
101 await ram.createPolicyVersion({
102 PolicyName: policyName,
103 PolicyDocument: JSON.stringify(policyDocument),
104 SetAsDefault: true
105 });
106 }
107 } catch (ex) {
108 if (ex.code && ex.code === 'NoPermission') {
109 throw ex;
110 }
111 console.log(red(`retry ${times} times`));
112 retry(ex);
113 }
114 });
115}
116
117async function attachPolicyToRole(policyName, roleName, policyType = 'System') {
118 const ram = await getRamClient();
119
120 await promiseRetry(async (retry, times) => {
121 try {
122 const policies = await ram.listPoliciesForRole({
123 RoleName: roleName
124 });
125 var policy = policies.Policies.Policy.find((item) => {
126 return _.toLower(item.PolicyName) === _.toLower(policyName);
127 });
128 if (!policy) {
129 await ram.attachPolicyToRole({
130 PolicyType: policyType,
131 PolicyName: policyName,
132 RoleName: roleName
133 });
134 }
135 } catch (ex) {
136 if (ex.code && ex.code === 'NoPermission') {
137 throw ex;
138 }
139 debug('error when attachPolicyToRole: %s, policyName %s, error is: \n%O', roleName, policyName, ex);
140
141 console.log(red(`retry ${times} times`));
142 retry(ex);
143 }
144 });
145}
146
147async function getRamRole(ramClient, roleName) {
148 try {
149 return await ramClient.getRole({
150 RoleName: roleName
151 });
152 } catch (ex) {
153 debug('error when getRole: %s, error is: \n%O', roleName, ex);
154 if (ex.name !== 'EntityNotExist.RoleError') {
155 throw ex;
156 }
157 }
158}
159
160async function makeRole(roleName, createRoleIfNotExist, description = 'FunctionCompute Default Role', assumeRolePolicy) {
161
162 const ram = await getRamClient();
163 var role;
164 await promiseRetry(async (retry, times) => {
165 try {
166 role = await getRamRole(ram, roleName);
167
168 if (!assumeRolePolicy) {
169 assumeRolePolicy = {
170 'Statement': [
171 {
172 'Action': 'sts:AssumeRole',
173 'Effect': 'Allow',
174 'Principal': {
175 'Service': [
176 'fc.aliyuncs.com'
177 ]
178 }
179 }
180 ],
181 'Version': '1'
182 };
183 }
184
185 if (!role && createRoleIfNotExist) {
186 role = await ram.createRole({
187 RoleName: roleName,
188 Description: description,
189 AssumeRolePolicyDocument: JSON.stringify(assumeRolePolicy)
190 });
191 } else if (!role) {
192 throw new Error(`role ${roleName} not exist`);
193 }
194 } catch (ex) {
195 debug('error when makeRole: %s, error is: \n%O', roleName, ex);
196
197 if (ex.code && ex.code.startsWith('InvalidParameter')) {
198 throw ex;
199 } else if (ex.code && ex.code === 'NoPermission') {
200 throw ex;
201 } else {
202 console.log(red(`retry ${times} times`));
203 retry(ex);
204 }
205 }
206 });
207
208 return role;
209}
210
211async function makeAndAttachPolicy(policyName, policyDocument, roleName) {
212 debug('begin makePolicy');
213 await makePolicy(policyName, policyDocument);
214 debug('begin attachPolicyToRole');
215 await attachPolicyToRole(policyName, roleName, 'Custom');
216}
217
218module.exports = {
219 makeRole, makePolicy,
220 attachPolicyToRole, makeAndAttachPolicy,
221 normalizeRoleOrPoliceName,
222 FNF_ASSUME_ROLE_POLICY
223};
\No newline at end of file