1
+ const {
2
+ LOG_LEVEL = 'info'
3
+ } = process . env ;
4
+
1
5
const { execSync} = require ( 'child_process' ) ;
2
6
const pascalcase = require ( 'pascalcase' ) ;
3
7
const fs = require ( 'fs' ) ;
@@ -9,71 +13,85 @@ const DEFAULT_CONFIG = {
9
13
exportPrefix : '${AWS::StackName}-'
10
14
} ;
11
15
12
- function getLayers ( serverless ) {
13
- return serverless . service . layers || { } ;
14
- }
15
-
16
- function getConfig ( serverless ) {
17
- const custom = serverless . service . custom || { } ;
18
-
19
- return { ...DEFAULT_CONFIG , ...custom . layerConfig } ;
20
- }
16
+ const LEVELS = {
17
+ none : 0 ,
18
+ info : 1 ,
19
+ verbose : 2
20
+ } ;
21
21
22
22
function log ( ...s ) {
23
23
console . log ( '[layer-manager]' , ...s ) ;
24
24
}
25
25
26
26
function verbose ( { level} , ...s ) {
27
- level === ' verbose' && log ( ...s ) ;
27
+ LEVELS [ level ] >= LEVELS . verbose && log ( ...s ) ;
28
28
}
29
29
30
30
function info ( { level} , ...s ) {
31
- log ( ...s ) ;
31
+ LEVELS [ level ] >= LEVELS . info && log ( ...s ) ;
32
32
}
33
33
34
+ function getLayers ( serverless ) {
35
+ return serverless . service . layers || { } ;
36
+ }
37
+
38
+ function getConfig ( serverless ) {
39
+ const custom = serverless . service . custom || { } ;
40
+
41
+ return { ...DEFAULT_CONFIG , ...custom . layerConfig } ;
42
+ }
34
43
35
44
class LayerManagerPlugin {
36
45
constructor ( sls , options = { } ) {
37
- this . level = options . v || options . verbose ? 'verbose' : 'info' ;
46
+ this . level = options . v || options . verbose ? 'verbose' : LOG_LEVEL ;
47
+ this . config = getConfig ( sls ) ;
38
48
39
49
info ( this , `Invoking layer-manager plugin` ) ;
50
+ verbose ( this , `Config: ` , this . config ) ;
40
51
41
52
this . hooks = {
42
53
'package:initialize' : ( ) => this . installLayers ( sls ) ,
43
54
'before:deploy:deploy' : ( ) => this . transformLayerResources ( sls )
44
55
} ;
45
56
}
46
57
58
+ installLayer ( path ) {
59
+ const nodeLayerPath = `${ path } /nodejs` ;
60
+
61
+ if ( fs . existsSync ( nodeLayerPath ) ) {
62
+ verbose ( this , `Installing nodejs layer ${ path } ` ) ;
63
+ execSync ( `npm install --prefix ${ nodeLayerPath } ` , {
64
+ stdio : 'inherit'
65
+ } ) ;
66
+ return true ;
67
+ }
68
+
69
+ return false ;
70
+ }
71
+
47
72
installLayers ( sls ) {
48
- const config = getConfig ( sls ) ;
73
+ const { installLayers } = this . config ;
49
74
50
- if ( ! config . installLayers ) {
75
+ if ( ! installLayers ) {
76
+ verbose ( this , `Skipping installation of layers as per config` ) ;
51
77
return ;
52
78
}
53
79
54
80
const layers = getLayers ( sls ) ;
55
- let i = 0 ;
56
- Object . values ( layers ) . forEach ( ( { path} ) => {
57
- const nodeLayerPath = `${ path } /nodejs` ;
58
-
59
- if ( fs . existsSync ( nodeLayerPath ) ) {
60
- verbose ( this , `Installing nodejs layer ${ path } ` ) ;
61
- execSync ( `npm install --prefix ${ nodeLayerPath } ` , {
62
- stdio : 'inherit'
63
- } ) ;
64
- i ++ ;
65
- }
66
- } ) ;
81
+ const installedLayers = Object . values ( layers )
82
+ . filter ( ( { path} ) => this . installLayer ( path ) ) ;
83
+
84
+ info ( this , `Installed ${ installedLayers . length } layers` ) ;
67
85
68
- info ( this , `Installed ${ i } layers` ) ;
86
+ return { installedLayers } ;
69
87
}
70
88
71
89
transformLayerResources ( sls ) {
72
- const config = getConfig ( sls ) ;
90
+ const { exportLayers , exportPrefix , upgradeLayerReferences } = this . config ;
73
91
const layers = getLayers ( sls ) ;
74
92
const { compiledCloudFormationTemplate : cf } = sls . service . provider ;
75
93
76
- Object . keys ( layers ) . forEach ( id => {
94
+ return Object . keys ( layers ) . reduce ( ( result , id ) => {
77
95
const name = pascalcase ( id ) ;
78
96
const exportName = `${ name } LambdaLayerQualifiedArn` ;
79
97
const output = cf . Outputs [ exportName ] ;
@@ -82,28 +100,30 @@ class LayerManagerPlugin {
82
100
return ;
83
101
}
84
102
85
- if ( config . exportLayers ) {
103
+ if ( exportLayers ) {
86
104
output . Export = {
87
105
Name : {
88
- 'Fn::Sub' : config . exportPrefix + exportName
106
+ 'Fn::Sub' : exportPrefix + exportName
89
107
}
90
108
} ;
109
+ result . exportedLayers . push ( output ) ;
91
110
}
92
111
93
- if ( config . upgradeLayerReferences ) {
112
+ if ( upgradeLayerReferences ) {
94
113
const resourceRef = `${ name } LambdaLayer` ;
95
114
const versionedResourceRef = output . Value . Ref ;
96
115
97
116
if ( resourceRef !== versionedResourceRef ) {
98
117
info ( this , `Replacing references to ${ resourceRef } with ${ versionedResourceRef } ` ) ;
99
118
100
119
Object . entries ( cf . Resources )
101
- . forEach ( ( [ id , { Type, Properties : { Layers = [ ] } = { } } ] ) => {
102
- if ( Type === 'AWS::Lambda::Function' ) {
103
- Layers . forEach ( Layer => {
104
- if ( Layer . Ref === resourceRef ) {
120
+ . forEach ( ( [ id , { Type : type , Properties : { Layers : layers = [ ] } = { } } ] ) => {
121
+ if ( type === 'AWS::Lambda::Function' ) {
122
+ layers . forEach ( layer => {
123
+ if ( layer . Ref === resourceRef ) {
105
124
verbose ( this , `${ id } : Updating reference to layer version ${ versionedResourceRef } ` ) ;
106
- Layer . Ref = versionedResourceRef ;
125
+ layer . Ref = versionedResourceRef ;
126
+ result . upgradedLayerReferences . push ( layer ) ;
107
127
}
108
128
} )
109
129
}
@@ -112,6 +132,11 @@ class LayerManagerPlugin {
112
132
}
113
133
114
134
verbose ( this , 'CF after transformation:\n' , JSON . stringify ( cf , null , 2 ) ) ;
135
+
136
+ return result ;
137
+ } , {
138
+ exportedLayers : [ ] ,
139
+ upgradedLayerReferences : [ ]
115
140
} ) ;
116
141
}
117
142
}
0 commit comments