22# SPDX-License-Identifier: MIT-0
33
44import json , os , copy
5- import boto3
5+ import boto3 , requests
66from jinja2 import Template
7+ from bs4 import BeautifulSoup
78
89s3 = boto3 .client ('s3' )
910s3_r = boto3 .resource ('s3' )
1819ACT_RUNTIMES = os .environ ['ACT_RUNTIMES' ]
1920STACK_NAME = os .environ ['STACK_NAME' ]
2021TA_ENABLED = os .environ ['TA_ENABLED' ]
22+ DOC_URL = "https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html"
2123
2224
2325###################################################################################################################################
24- #Deprecated runtime evaluation code functionality
26+ # Runtime evaluation code functionality
2527###################################################################################################################################
26- def check_deprecated_runtime (fns ):
27- run_check = fns
28- act_runtimes = str .split (ACT_RUNTIMES , ',' )
29-
30- for fn in run_check :
31- match = False
32- if fn ['PackageType' ] == 'Image' :
33- fn ['Runtime' ] = 'Container'
34- for run in act_runtimes :
35- if run == fn ['Runtime' ]:
36- match = True
28+ def check_dep_runtime (fns ,dep_runs ):
29+ # Create a dictionary to map Identifiers to runtime details
30+ runtime_map = {item ['Identifier' ]: {
31+ 'Deprecation date' : item ['Deprecation date' ],
32+ 'Block function create' : item ['Block function create' ],
33+ 'Block function update' : item ['Block function update' ]
34+ } for item in dep_runs ['Deprecated Runtimes' ]}
35+
36+ # Iterate through the function data and append the runtime details
37+ for function in fns :
38+ runtime = function ['Runtime' ]
39+ for identifier , details in runtime_map .items ():
40+ if runtime == identifier :
41+ function ['Deprecation date' ] = details ['Deprecation date' ]
42+ function ['Block function create' ] = details ['Block function create' ]
43+ function ['Block function update' ] = details ['Block function update' ]
44+ break
45+
46+ return fns
47+
48+ def check_sup_runtime (fns ,sup_runs ):
49+ # Create a dictionary to map Identifiers to runtime details
50+ runtime_map = {item ['Identifier' ]: {
51+ 'Deprecation date' : item ['Deprecation date' ],
52+ 'Block function create' : item ['Block function create' ],
53+ 'Block function update' : item ['Block function update' ]
54+ } for item in sup_runs ['Supported Runtimes' ]}
55+
56+ # Iterate through the function data and append the runtime details
57+ for function in fns :
58+ runtime = function ['Runtime' ]
59+ for identifier , details in runtime_map .items ():
60+ if runtime == identifier :
61+ function ['Deprecation date' ] = details ['Deprecation date' ]
62+ function ['Block function create' ] = details ['Block function create' ]
63+ function ['Block function update' ] = details ['Block function update' ]
3764 break
38- if match == False :
39- fn ['Message' ] = 'Function is using older or deprecated runtime, consider updating.'
40- else :
41- fn ['Message' ] = 'Function runtime is one of latest.'
4265
43- return run_check
66+ return fns
67+
4468
4569###################################################################################################################################
4670
@@ -164,6 +188,68 @@ def check_multi_az(fns):
164188
165189###################################################################################################################################
166190
191+ ###################################################################################################################################
192+ #Deprecated runtime fetch:
193+ ###################################################################################################################################
194+ def fetch_deprecated_runtimes (dep_run_soup ):
195+ """
196+ Fetch the list of deprecated runtimes from the AWS Lambda docs
197+ """
198+ # Find the Deprecated Runtime table
199+ element = dep_run_soup .find (id = "runtimes-deprecated" )
200+ table = element .find_next ("table" )
201+
202+ # Extract header row
203+ headers = [header .text for header in table .find ('thead' ).find_all ('tr' )]
204+ headers = headers [1 ]
205+ headers = headers .split ('\n ' )
206+ headers = headers [1 :- 1 ]
207+
208+ rows = []
209+
210+ for row in table .find_all ('tr' )[1 :]:
211+ cells = row .find_all ('td' )
212+ data = [cell .text for cell in cells ]
213+ data = [line .strip () for line in data ]
214+ rows .append (dict (zip (headers , data )))
215+ rows = rows [1 :]
216+
217+
218+ return rows
219+ ###################################################################################################################################
220+
221+ ###################################################################################################################################
222+ #Supported runtime fetch:
223+ ###################################################################################################################################
224+
225+ def fetch_supported_runtimes (sup_run_soup ):
226+ """
227+ Fetch the list of supported runtimes from the AWS Lambda docs
228+ """
229+ # Find the Supported Runtime table
230+ element = sup_run_soup .find (id = "runtimes-supported" )
231+ table = element .find_next ("table" )
232+
233+ # Extract header row
234+ headers = [header .text for header in table .find ('thead' ).find_all ('tr' )]
235+ headers = headers [1 ]
236+ headers = headers .split ('\n ' )
237+ headers = headers [1 :- 1 ]
238+
239+ rows = []
240+
241+ for row in table .find_all ('tr' )[1 :]:
242+ cells = row .find_all ('td' )
243+ data = [cell .text for cell in cells ]
244+ data = [line .strip () for line in data ]
245+ rows .append (dict (zip (headers , data )))
246+ rows = rows [1 :]
247+
248+
249+ return rows
250+
251+ ###################################################################################################################################
252+
167253def handler (event , context ):
168254 #List function config objects from S3:
169255 s3_prefix = event ['Prefix' ]
@@ -195,33 +281,110 @@ def handler(event, context):
195281
196282
197283 #################################################################################
198- #Deprecated runtime evaluation method pointer:
199- #################################################################################
200- run_fns = copy .deepcopy (functions )
201- warnings_dep_runtime = check_deprecated_runtime (run_fns )
284+ #Runtime evaluation method pointer:
285+ #################################################################################
286+
287+ html = requests .get (DOC_URL )
288+ html = html .text
289+
290+ soup = BeautifulSoup (html , 'html.parser' )
291+
292+ supported_runtimes = {'Supported Runtimes' : fetch_supported_runtimes (soup )}
293+
294+ deprecated_runtimes = {'Deprecated Runtimes' : fetch_deprecated_runtimes (soup )}
295+
296+ dep_fns = copy .deepcopy (functions )
297+ dep_runtime_fns = check_dep_runtime (dep_fns ,deprecated_runtimes )
298+ sup_fns = copy .deepcopy (functions )
299+ sup_runtime_fns = check_sup_runtime (sup_fns ,supported_runtimes )
300+
301+ # Separate deprecated functions by runtime:
202302 py_dep_run = []
303+ for function in dep_runtime_fns :
304+ runtime = function ['Runtime' ]
305+ if runtime .startswith ('python' ) and 'Deprecation date' in function and function ['Deprecation date' ] != '' :
306+ py_dep_run .append (function )
307+
203308 no_dep_run = []
309+ for function in dep_runtime_fns :
310+ runtime = function ['Runtime' ]
311+ if runtime .startswith ('nodejs' ) and 'Deprecation date' in function and function ['Deprecation date' ] != '' :
312+ no_dep_run .append (function )
313+
204314 ja_dep_run = []
315+ for function in dep_runtime_fns :
316+ runtime = function ['Runtime' ]
317+ if runtime .startswith ('java' ) and 'Deprecation date' in function and function ['Deprecation date' ] != '' :
318+ ja_dep_run .append (function )
319+
205320 do_dep_run = []
321+ for function in dep_runtime_fns :
322+ runtime = function ['Runtime' ]
323+ if runtime .startswith ('dotnet' ) and 'Deprecation date' in function and function ['Deprecation date' ] != '' :
324+ do_dep_run .append (function )
325+
206326 ru_dep_run = []
327+ for function in dep_runtime_fns :
328+ runtime = function ['Runtime' ]
329+ if runtime .startswith ('ruby' ) and 'Deprecation date' in function and function ['Deprecation date' ] != '' :
330+ ru_dep_run .append (function )
331+
207332 go_dep_run = []
333+ for function in dep_runtime_fns :
334+ runtime = function ['Runtime' ]
335+ if runtime .startswith ('golang' ) and 'Deprecation date' in function and function ['Deprecation date' ] != '' :
336+ go_dep_run .append (function )
337+
208338 cu_dep_run = []
209- for run_warning in warnings_dep_runtime :
210- if run_warning ['Message' ] != 'Function runtime is one of latest.' :
211- if run_warning ['Runtime' ].startswith ('python' ):
212- py_dep_run .append (run_warning )
213- elif run_warning ['Runtime' ].startswith ('nodejs' ):
214- no_dep_run .append (run_warning )
215- elif run_warning ['Runtime' ].startswith ('java' ):
216- ja_dep_run .append (run_warning )
217- elif run_warning ['Runtime' ].startswith ('dotnet' ):
218- do_dep_run .append (run_warning )
219- elif run_warning ['Runtime' ].startswith ('ruby' ):
220- ru_dep_run .append (run_warning )
221- elif run_warning ['Runtime' ].startswith ('golang' ):
222- go_dep_run .append (run_warning )
223- elif run_warning ['Runtime' ].startswith ('provided' ):
224- cu_dep_run .append (run_warning )
339+ for function in dep_runtime_fns :
340+ runtime = function ['Runtime' ]
341+ if runtime .startswith ('provided' ) and 'Deprecation date' in function and function ['Deprecation date' ] != '' :
342+ cu_dep_run .append (function )
343+
344+
345+ # Separate supported functions by runtime:
346+ py_sup_run = []
347+ for function in sup_runtime_fns :
348+ runtime = function ['Runtime' ]
349+ if runtime .startswith ('python' ) and 'Deprecation date' in function and function ['Deprecation date' ] != '' :
350+ py_sup_run .append (function )
351+
352+ no_sup_run = []
353+ for function in sup_runtime_fns :
354+ runtime = function ['Runtime' ]
355+ if runtime .startswith ('nodejs' ) and 'Deprecation date' in function and function ['Deprecation date' ] != '' :
356+ no_sup_run .append (function )
357+
358+ ja_sup_run = []
359+ for function in sup_runtime_fns :
360+ runtime = function ['Runtime' ]
361+ if runtime .startswith ('java' ) and 'Deprecation date' in function and function ['Deprecation date' ] != '' :
362+ ja_sup_run .append (function )
363+
364+ do_sup_run = []
365+ for function in sup_runtime_fns :
366+ runtime = function ['Runtime' ]
367+ if runtime .startswith ('dotnet' ) and 'Deprecation date' in function and function ['Deprecation date' ] != '' :
368+ do_sup_run .append (function )
369+
370+ ru_sup_run = []
371+ for function in sup_runtime_fns :
372+ runtime = function ['Runtime' ]
373+ if runtime .startswith ('ruby' ) and 'Deprecation date' in function and function ['Deprecation date' ] != '' :
374+ ru_sup_run .append (function )
375+
376+ go_sup_run = []
377+ for function in sup_runtime_fns :
378+ runtime = function ['Runtime' ]
379+ if runtime .startswith ('golang' ) and 'Deprecation date' in function and function ['Deprecation date' ] != '' :
380+ go_sup_run .append (function )
381+
382+ cu_sup_run = []
383+ for function in sup_runtime_fns :
384+ runtime = function ['Runtime' ]
385+ if runtime .startswith ('provided' ) and 'Deprecation date' in function and function ['Deprecation date' ] != '' :
386+ cu_sup_run .append (function )
387+
225388
226389 #################################################################################
227390 #Trusted Advisor evaluations
@@ -292,16 +455,11 @@ def handler(event, context):
292455 if fn ['FunctionArn' ] == esm ['FunctionArn' ]:
293456 filtered_esms .append (esm )
294457
295- print (filtered_esms )
296-
297-
298-
299-
300458
301459 #################################################################################
302460
303461 #################################################################################
304- #Create a dict wilh all data that will populate the template
462+ #Create a dict with all data that will populate the template
305463 #################################################################################
306464 data = {}
307465 data ['account' ] = AWS_ACCOUNT
@@ -314,6 +472,13 @@ def handler(event, context):
314472 data ['dep_ruby_functions' ] = ru_dep_run
315473 data ['dep_golang_functions' ] = go_dep_run
316474 data ['dep_custom_functions' ] = cu_dep_run
475+ data ['sup_python_functions' ] = py_sup_run
476+ data ['sup_nodejs_functions' ] = no_sup_run
477+ data ['sup_java_functions' ] = ja_sup_run
478+ data ['sup_dotnet_functions' ] = do_sup_run
479+ data ['sup_ruby_functions' ] = ru_sup_run
480+ data ['sup_golang_functions' ] = go_sup_run
481+ data ['sup_custom_functions' ] = cu_sup_run
317482 if TA_ENABLED == 'true' :
318483 data ['warnings_ta_high_errors' ] = warnings_ta_high_errors
319484 data ['warnings_ta_excessive_timeouts' ] = warnings_ta_excessive_timeout
0 commit comments