1
1
package lambda
2
2
3
3
import (
4
+ "errors"
4
5
"fmt"
5
6
"log"
6
7
"os"
@@ -15,48 +16,114 @@ const Type = "lambda"
15
16
16
17
var logger = log .New (os .Stdout , fmt .Sprintf ("[%s] " , Type ), log .LstdFlags )
17
18
19
+ type Layer struct {
20
+ LayerARN * string
21
+ Version * int64
22
+ }
23
+
18
24
func Clean (sess * session.Session , expirationDate time.Time ) error {
19
- logger .Printf ("Begin to clean Lambda functions" )
25
+ return errors .Join (cleanFunctions (sess , expirationDate ), cleanLayers (sess , expirationDate ))
26
+ }
20
27
21
- lambdaclient := lambda .New (sess )
28
+ func cleanFunctions (sess * session.Session , expirationDate time.Time ) error {
29
+ logger .Printf ("Begin to clean Lambda functions" )
30
+ lambdaClient := lambda .New (sess )
22
31
var deleteFunctionIDs []* string
23
32
var nextToken * string
33
+
24
34
for {
25
- ListFunctionsInput := & lambda.ListFunctionsInput {Marker : nextToken }
26
- ListFunctionsOutput , err := lambdaclient .ListFunctions (ListFunctionsInput )
35
+ listFunctionsInput := & lambda.ListFunctionsInput {Marker : nextToken }
36
+ listFunctionsOutput , err := lambdaClient .ListFunctions (listFunctionsInput )
27
37
if err != nil {
28
- return fmt .Errorf ("unable to retrieve APIs : %w" , err )
38
+ return fmt .Errorf ("unable to retrieve functions : %w" , err )
29
39
}
30
- for _ , lf := range ListFunctionsOutput .Functions {
40
+
41
+ for _ , lf := range listFunctionsOutput .Functions {
31
42
doesNameMatch , err := shouldDelete (lf )
32
43
if err != nil {
33
44
return fmt .Errorf ("error during pattern match: %w" , err )
34
45
}
35
46
created , err := time .Parse ("2006-01-02T15:04:05Z0700" , * lf .LastModified )
36
47
if err != nil {
37
- return fmt .Errorf ("error parting last modified time: %w" , err )
48
+ return fmt .Errorf ("error parsing last modified time: %w" , err )
38
49
}
39
50
if expirationDate .After (created ) && doesNameMatch {
40
51
logger .Printf ("Try to delete function %s created-at %s" , * lf .FunctionArn , * lf .LastModified )
41
52
deleteFunctionIDs = append (deleteFunctionIDs , lf .FunctionArn )
42
53
}
43
54
}
44
- if ListFunctionsOutput .NextMarker == nil {
55
+ if listFunctionsOutput .NextMarker == nil {
45
56
break
46
57
}
47
- nextToken = ListFunctionsOutput .NextMarker
58
+ nextToken = listFunctionsOutput .NextMarker
48
59
}
49
60
if len (deleteFunctionIDs ) < 1 {
50
61
logger .Printf ("No Lambda functions to delete" )
51
62
return nil
52
63
}
53
-
54
64
for _ , id := range deleteFunctionIDs {
55
65
terminateFunctionInput := & lambda.DeleteFunctionInput {FunctionName : id }
56
- if _ , err := lambdaclient .DeleteFunction (terminateFunctionInput ); err != nil {
66
+ if _ , err := lambdaClient .DeleteFunction (terminateFunctionInput ); err != nil {
57
67
return fmt .Errorf ("unable to delete function: %w" , err )
58
68
}
69
+ logger .Printf ("Deleted %d Lambda functions" , len (deleteFunctionIDs ))
70
+ }
71
+
72
+ return nil
73
+ }
74
+
75
+ func cleanLayers (sess * session.Session , expirationDate time.Time ) error {
76
+ logger .Printf ("Begin to clean Lambda layers" )
77
+ lambdaClient := lambda .New (sess )
78
+ var deleteLayerVersions []Layer
79
+ var nextToken * string
80
+
81
+ for {
82
+ listLayerVersionsInput := & lambda.ListLayersInput {
83
+ Marker : nextToken ,
84
+ }
85
+
86
+ // Retrieve layer versions from Lambda service
87
+ listLayerVersionsOutput , err := lambdaClient .ListLayers (listLayerVersionsInput )
88
+ if err != nil {
89
+ return fmt .Errorf ("unable to retrieve layer versions: %w" , err )
90
+ }
91
+
92
+ // Loop through retrieved layer versions
93
+ for _ , layer := range listLayerVersionsOutput .Layers {
94
+
95
+ if shouldDeleteLayer (layer , expirationDate ) {
96
+ logger .Printf ("Try to delete layer version %s created-at %s" , * layer .LayerArn , * layer .LatestMatchingVersion .CreatedDate )
97
+ deleteLayerVersions = append (deleteLayerVersions , Layer {layer .LayerArn , layer .LatestMatchingVersion .Version })
98
+ }
99
+ }
100
+
101
+ if listLayerVersionsOutput .NextMarker == nil {
102
+ break
103
+ }
104
+ nextToken = listLayerVersionsOutput .NextMarker
105
+ }
106
+
107
+ if len (deleteLayerVersions ) < 1 {
108
+ logger .Printf ("No Lambda layers to delete" )
109
+ return nil
110
+ }
111
+ for _ , id := range deleteLayerVersions {
112
+ for * id .Version > 0 {
113
+ // Prepare input for deleting a specific layer version
114
+ deleteLayerVersionInput := & lambda.DeleteLayerVersionInput {
115
+ LayerName : id .LayerARN ,
116
+ VersionNumber : id .Version ,
117
+ }
118
+ if _ , err := lambdaClient .DeleteLayerVersion (deleteLayerVersionInput ); err != nil {
119
+ return fmt .Errorf ("unable to delete layer version: %w" , err )
120
+ }
121
+ // Decrement the version number for the next iteration
122
+ * id .Version --
123
+ }
124
+ logger .Printf ("Deleted %d Lambda layer versions" , len (deleteLayerVersions ))
59
125
}
126
+
60
127
return nil
61
128
}
62
129
@@ -79,3 +146,31 @@ func shouldDelete(lf *lambda.FunctionConfiguration) (bool, error) {
79
146
}
80
147
return false , nil
81
148
}
149
+
150
+ func shouldDeleteLayer (layerList * lambda.LayersListItem , expirationDate time.Time ) bool {
151
+ layerARN := layerList .LayerArn
152
+ regexList := []string {
153
+ ".*:layer:aws-otel-collector.*$" ,
154
+ ".*:layer:aws-otel-lambda-python.*$" ,
155
+ ".*:layer:aws-otel-java.*$" ,
156
+ ".*:layer:aws-otel-lambda-nodejs.*$" ,
157
+ ".*:layer:aws-otel-go-wrapper.*$" ,
158
+ ".*:layer:aws-observability.*$" ,
159
+ ".*:layer:aws-distro-for-opentelemetry.*$" ,
160
+ }
161
+
162
+ for _ , rx := range regexList {
163
+ matched , _ := regexp .MatchString (rx , * layerARN )
164
+ if matched {
165
+ created , err := time .Parse ("2006-01-02T15:04:05Z0700" , * layerList .LatestMatchingVersion .CreatedDate )
166
+ if err != nil {
167
+ logger .Printf ("Error Parsing the created time for layer %s" , err )
168
+ return false
169
+ }
170
+ if expirationDate .After (created ) {
171
+ return true
172
+ }
173
+ }
174
+ }
175
+ return false
176
+ }
0 commit comments