@@ -13,94 +13,51 @@ module.exports = function(currentTemplate, aliasStackTemplates, currentAliasStac
13
13
14
14
const stageStack = this . _serverless . service . provider . compiledCloudFormationTemplate ;
15
15
const aliasStack = this . _serverless . service . provider . compiledCloudFormationAliasTemplate ;
16
- let stageRolePolicies = _ . get ( stageStack , 'Resources.IamRoleLambdaExecution.Properties.Policies' , [ ] ) ;
17
- let currentRolePolicies = _ . get ( currentTemplate , 'Resources.IamRoleLambdaExecution.Properties.Policies' , [ ] ) ;
18
-
19
- // Older serverless versions (<1.7.0) do not use a inline policy.
20
- if ( _ . isEmpty ( currentRolePolicies ) && _ . has ( currentTemplate , 'Resources.IamPolicyLambdaExecution' ) ) {
21
- this . _serverless . cli . log ( 'WARNING: Project created with SLS < 1.7.0. Using resources from policy.' ) ;
22
- currentRolePolicies = [ _ . get ( currentTemplate , 'Resources.IamPolicyLambdaExecution.Properties' ) ] ;
23
- }
24
- if ( _ . isEmpty ( stageRolePolicies ) && _ . has ( stageStack , 'Resources.IamPolicyLambdaExecution' ) ) {
25
- stageRolePolicies = [ _ . get ( stageStack , 'Resources.IamPolicyLambdaExecution.Properties' ) ] ;
26
- }
27
16
28
17
// There can be a service role defined. In this case there is no embedded IAM role.
29
18
if ( _ . has ( this . _serverless . service . provider , 'role' ) ) {
30
19
// Use the role if any of the aliases reference it
31
- if ( ! _ . isEmpty ( currentRolePolicies ) &&
32
- _ . some ( aliasStackTemplates , template => ! template . Outputs . AliasFlags . Value . hasRole ) ) {
33
- stageStack . Resources . IamRoleLambdaExecution = _ . cloneDeep ( currentTemplate . Resources . IamRoleLambdaExecution ) ;
34
- }
35
-
36
20
aliasStack . Outputs . AliasFlags . Value . hasRole = true ;
37
21
38
- return BbPromise . resolve ( [ currentTemplate , aliasStackTemplates , currentAliasStackTemplate ] ) ;
39
- }
40
-
41
- // For now we only merge the first policy document and exit if SLS changes this behavior.
42
- if ( stageRolePolicies . length !== 1 ) {
43
- return BbPromise . reject ( new Error ( 'Policy count should be 1! Please report this error to the alias plugin owner.' ) ) ;
44
- }
22
+ // Import all defined roles from the current template (without overwriting)
23
+ const currentRoles = _ . assign ( { } , _ . pickBy ( currentTemplate . Resources , ( resource , name ) => resource . Type === 'AWS::IAM::Role' && / ^ I a m R o l e L a m b d a E x e c u t i o n / . test ( name ) ) ) ;
24
+ _ . defaults ( stageStack . Resources , currentRoles ) ;
45
25
46
- const stageRolePolicyStatements = _ . get ( stageRolePolicies [ 0 ] , 'PolicyDocument.Statement' , [ ] ) ;
47
- const currentRolePolicyStatements = _ . get ( currentRolePolicies [ 0 ] , 'PolicyDocument.Statement' , [ ] ) ;
26
+ // Remove old role for this alias
27
+ delete stageStack . Resources [ `IamRoleLambdaExecution ${ this . _alias } ` ] ;
48
28
49
- _ . forEach ( currentRolePolicyStatements , statement => {
50
- // Check if there is already a statement with the same actions and effect.
51
- const sameStageStatement = _ . find ( stageRolePolicyStatements , value => value . Effect === statement . Effect &&
52
- value . Action . length === statement . Action . length &&
53
- _ . every ( value . Action , action => _ . includes ( statement . Action , action ) ) ) ;
54
-
55
- if ( sameStageStatement ) {
56
- // Merge the resources
57
- sameStageStatement . Resource = _ . uniqWith ( _ . concat ( sameStageStatement . Resource , statement . Resource ) , ( a , b ) => _ . isEqual ( a , b ) ) ;
58
- } else {
59
- // Add the different statement
60
- stageRolePolicyStatements . push ( statement ) ;
61
- }
62
- } ) ;
29
+ return BbPromise . resolve ( [ currentTemplate , aliasStackTemplates , currentAliasStackTemplate ] ) ;
30
+ }
63
31
64
- // Remove all resource references of removed resources
65
- const voidResourceRefs = utils . findReferences ( stageRolePolicyStatements , this . removedResourceKeys ) ;
66
- const voidResourcePtrs = _ . compact ( _ . map ( voidResourceRefs , ref => {
67
- const ptrs = / \[ ( [ 0 - 9 ] + ) \] .R e s o u r c e \[ ( [ 0 - 9 ] + ) \] .* / . exec ( ref ) ;
68
- if ( ptrs && ptrs . length === 3 ) {
69
- return { s : ptrs [ 1 ] , r : ptrs [ 2 ] } ;
70
- }
71
- return null ;
72
- } ) ) ;
73
- _ . forEach ( voidResourcePtrs , ptr => {
74
- const statement = stageRolePolicyStatements [ ptr . s ] ;
75
- _ . pullAt ( statement . Resource , [ ptr . r ] ) ;
76
- if ( _ . isEmpty ( statement . Resource ) ) {
77
- _ . pullAt ( stageRolePolicyStatements , [ ptr . s ] ) ;
78
- }
32
+ const roleName = `IamRoleLambdaExecution${ this . _alias } ` ;
33
+ const role = stageStack . Resources . IamRoleLambdaExecution ;
34
+
35
+ // Set role name
36
+ _ . last ( role . Properties . RoleName [ 'Fn::Join' ] ) . push ( this . _alias ) ;
37
+
38
+ stageStack . Resources [ roleName ] = stageStack . Resources . IamRoleLambdaExecution ;
39
+ delete stageStack . Resources . IamRoleLambdaExecution ;
40
+
41
+ // Replace references
42
+ const functions = _ . filter ( stageStack . Resources , [ 'Type' , 'AWS::Lambda::Function' ] ) ;
43
+ _ . forEach ( functions , func => {
44
+ func . Properties . Role = {
45
+ 'Fn::GetAtt' : [
46
+ roleName ,
47
+ 'Arn'
48
+ ]
49
+ } ;
50
+ const dependencyIndex = _ . indexOf ( func . DependsOn , 'IamRoleLambdaExecution' ) ;
51
+ func . DependsOn [ dependencyIndex ] = roleName ;
79
52
} ) ;
80
53
81
- // Insert statement dependencies
82
- const dependencies = _ . reject ( ( ( ) => {
83
- const result = [ ] ;
84
- const stack = [ _ . first ( stageRolePolicyStatements ) ] ;
85
- while ( ! _ . isEmpty ( stack ) ) {
86
- const statement = stack . pop ( ) ;
87
-
88
- _ . forOwn ( statement , ( value , key ) => {
89
- if ( key === 'Ref' ) {
90
- result . push ( value ) ;
91
- } else if ( key === 'Fn::GetAtt' ) {
92
- result . push ( value [ 0 ] ) ;
93
- } else if ( _ . isObject ( value ) ) {
94
- stack . push ( value ) ;
95
- }
96
- } ) ;
97
- }
98
- return result ;
99
- } ) ( ) , dependency => _ . has ( stageStack . Resources , dependency ) ) ;
54
+ if ( _ . isEmpty ( utils . findReferences ( currentTemplate . Resources , 'IamRoleLambdaExecution' ) ) && _ . has ( currentTemplate , 'Resources.IamRoleLambdaExecution' ) ) {
55
+ delete currentTemplate . Resources . IamRoleLambdaExecution ;
56
+ }
100
57
101
- _ . forEach ( dependencies , dependency => {
102
- stageStack . Resources [ dependency ] = currentTemplate . Resources [ dependency ] ;
103
- } ) ;
58
+ // Import all defined roles from the current template (without overwriting)
59
+ const currentRoles = _ . assign ( { } , _ . pickBy ( currentTemplate . Resources , ( resource , name ) => resource . Type === 'AWS::IAM::Role' && / ^ I a m R o l e L a m b d a E x e c u t i o n / . test ( name ) ) ) ;
60
+ _ . defaults ( stageStack . Resources , currentRoles ) ;
104
61
105
62
return BbPromise . resolve ( [ currentTemplate , aliasStackTemplates , currentAliasStackTemplate ] ) ;
106
63
} ;
0 commit comments