copy-lambdas.yaml 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. AWSTemplateFormatVersion: '2010-09-09'
  2. Description: This template creates an S3 bucket in the same region where the stack is launched and copy the Lambda functions code from original bucket to the new bucket. (qs-1qp7e9tkk)
  3. Parameters:
  4. QSS3BucketName:
  5. AllowedPattern: "^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$"
  6. ConstraintDescription: S3 bucket name can include numbers, lowercase letters,uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-).
  7. Default: ravpn-quickstart-test
  8. Description: Alphanumeric string which identifies the S3 bucket name for the QuickStart assets. It's the bucket to store the copy of the Quick Start assets if you decided to customize or extend them for your own use.
  9. Type: String
  10. QSS3KeyPrefix:
  11. AllowedPattern: "^[0-9a-zA-Z-/._]*$"
  12. ConstraintDescription: S3 key prefix can include numbers, lowercase letters, uppercaseletters, hyphens (-), and forward slash (/).
  13. Default: quickstart-cisco-asav-ravpn/
  14. Description: Alphanumeric string which identifies the S3 key prefix used to simulate a folder for your copy of the Quick Start assets if you decided to customize or extend them for your own use.
  15. Type: String
  16. Resources:
  17. CopyObjects:
  18. Properties:
  19. ServiceToken:
  20. Fn::GetAtt:
  21. - CopyObjectsFunction
  22. - Arn
  23. DestBucket:
  24. Ref: LambdaZipsBucket
  25. Objects:
  26. - functions/packages/lambda.zip
  27. SourceBucket:
  28. Ref: QSS3BucketName
  29. Prefix:
  30. Ref: QSS3KeyPrefix
  31. Type: AWS::CloudFormation::CustomResource
  32. CopyObjectsFunction:
  33. Properties:
  34. Code:
  35. ZipFile:
  36. Fn::Join:
  37. - "\n"
  38. - - import json
  39. - import logging
  40. - import threading
  41. - import boto3
  42. - import cfnresponse
  43. - ''
  44. - ''
  45. - 'def copy_objects(source_bucket, dest_bucket, prefix, objects):'
  46. - " s3 = boto3.client('s3')"
  47. - " for o in objects:"
  48. - " key = prefix + o"
  49. - " copy_source = {"
  50. - " 'Bucket': source_bucket,"
  51. - " 'Key': key"
  52. - " }"
  53. - " s3.copy_object(CopySource=copy_source, Bucket=dest_bucket,
  54. Key=key)"
  55. - ''
  56. - ''
  57. - 'def delete_objects(bucket):'
  58. - " client = boto3.client('s3')"
  59. - ' print(("Collecting data from" + bucket))'
  60. - " paginator = client.get_paginator('list_object_versions')"
  61. - " result = paginator.paginate(Bucket=bucket)"
  62. - " objects = []"
  63. - " for page in result:"
  64. - " try:"
  65. - " for k in page['Versions']:"
  66. - " objects.append({'Key':k['Key'],'VersionId': k['VersionId']})"
  67. - " try:"
  68. - " for k in page['DeleteMarkers']:"
  69. - " version = k['VersionId']"
  70. - " key = k['Key']"
  71. - " objects.append({'Key': key,'VersionId': version})"
  72. - " except:"
  73. - " pass"
  74. - ' print("deleting objects")'
  75. - " client.delete_objects(Bucket=bucket, Delete={'Objects':
  76. objects})"
  77. - " # objects = []"
  78. - " except:"
  79. - " pass"
  80. - ' print("bucket already empty")'
  81. - ''
  82. - ''
  83. - ''
  84. - 'def timeout(event, context):'
  85. - " logging.error('Execution is about to time out, sending failure
  86. response to CloudFormation')"
  87. - " cfnresponse.send(event, context, cfnresponse.FAILED, {}, None)"
  88. - ''
  89. - ''
  90. - 'def handler(event, context):'
  91. - " # make sure we send a failure to CloudFormation if the function
  92. is going to timeout"
  93. - " timer = threading.Timer((context.get_remaining_time_in_millis()
  94. / 1000.00) - 0.5, timeout, args=[event, context])"
  95. - " timer.start()"
  96. - ''
  97. - " print(('Received event: %s' % json.dumps(event)))"
  98. - " status = cfnresponse.SUCCESS"
  99. - " try:"
  100. - " source_bucket = event['ResourceProperties']['SourceBucket']"
  101. - " dest_bucket = event['ResourceProperties']['DestBucket']"
  102. - " prefix = event['ResourceProperties']['Prefix']"
  103. - " objects = event['ResourceProperties']['Objects']"
  104. - " if event['RequestType'] == 'Delete':"
  105. - " delete_objects(dest_bucket)"
  106. - " else:"
  107. - " copy_objects(source_bucket, dest_bucket, prefix, objects)"
  108. - " except Exception as e:"
  109. - " logging.error('Exception: %s' % e, exc_info=True)"
  110. - " status = cfnresponse.FAILED"
  111. - " finally:"
  112. - " timer.cancel()"
  113. - " cfnresponse.send(event, context, status, {}, None)"
  114. - ''
  115. Description: Copies objects from a source S3 bucket to a destination S3 bucket
  116. Handler: index.handler
  117. Role:
  118. Fn::GetAtt:
  119. - CopyObjectsRole
  120. - Arn
  121. Runtime: python3.7
  122. Timeout: 240
  123. Type: AWS::Lambda::Function
  124. CopyObjectsRole:
  125. Properties:
  126. AssumeRolePolicyDocument:
  127. Statement:
  128. - Action: sts:AssumeRole
  129. Effect: Allow
  130. Principal:
  131. Service: lambda.amazonaws.com
  132. Version: '2012-10-17'
  133. ManagedPolicyArns:
  134. - !Sub arn:${AWS::Partition}:iam::${AWS::Partition}:policy/service-role/AWSLambdaBasicExecutionRole
  135. Path: "/"
  136. Policies:
  137. - PolicyDocument:
  138. Statement:
  139. - Action:
  140. - s3:GetObject
  141. Effect: Allow
  142. Resource:
  143. - Fn::Sub: arn:${AWS::Partition}:s3:::${QSS3BucketName}/${QSS3KeyPrefix}*
  144. - Action:
  145. - s3:PutObject
  146. - s3:DeleteObject
  147. - s3:GetObject
  148. - s3:ListBucket
  149. - s3:ListBucketVersions
  150. - s3:DeleteObjectVersion
  151. - s3:GetObjectVersion
  152. - s3:GetBucketVersioning
  153. Effect: Allow
  154. Resource:
  155. - Fn::Sub: arn:${AWS::Partition}:s3:::${LambdaZipsBucket}/${QSS3KeyPrefix}*
  156. - Fn::Sub: arn:${AWS::Partition}:s3:::${LambdaZipsBucket}
  157. Version: '2012-10-17'
  158. PolicyName: object-copier
  159. Type: AWS::IAM::Role
  160. LambdaZipsBucket:
  161. Properties:
  162. Tags: []
  163. VersioningConfiguration:
  164. Status: Enabled
  165. Type: AWS::S3::Bucket
  166. CleanUpS3Bucket:
  167. Properties:
  168. DestBucket:
  169. Ref: LambdaZipsBucket
  170. ServiceToken:
  171. Fn::GetAtt:
  172. - CleanUpS3BucketFunction
  173. - Arn
  174. Type: AWS::CloudFormation::CustomResource
  175. CleanUpS3BucketFunction:
  176. Properties:
  177. Code:
  178. ZipFile:
  179. Fn::Join:
  180. - "\n"
  181. - - import json
  182. - import logging
  183. - import threading
  184. - import boto3
  185. - import cfnresponse
  186. - client = boto3.client('s3')
  187. - ''
  188. - ''
  189. - 'def delete_NonVersionedobjects(bucket):'
  190. - ' print(("Collecting data from" + bucket))'
  191. - " paginator = client.get_paginator('list_objects_v2')"
  192. - " result = paginator.paginate(Bucket=bucket)"
  193. - " objects = []"
  194. - " for page in result:"
  195. - " try:"
  196. - " for k in page['Contents']:"
  197. - " objects.append({'Key': k['Key']})"
  198. - ' print("deleting objects")'
  199. - " client.delete_objects(Bucket=bucket, Delete={'Objects':
  200. objects})"
  201. - " objects = []"
  202. - " except:"
  203. - " pass"
  204. - ' print("bucket is already empty")'
  205. - ''
  206. - 'def delete_versionedobjects(bucket):'
  207. - ' print(("Collecting data from" + bucket))'
  208. - " paginator = client.get_paginator('list_object_versions')"
  209. - " result = paginator.paginate(Bucket=bucket)"
  210. - " objects = []"
  211. - " for page in result:"
  212. - " try:"
  213. - " for k in page['Versions']:"
  214. - " objects.append({'Key':k['Key'],'VersionId': k['VersionId']})"
  215. - " try:"
  216. - " for k in page['DeleteMarkers']:"
  217. - " version = k['VersionId']"
  218. - " key = k['Key']"
  219. - " objects.append({'Key': key,'VersionId': version})"
  220. - " except:"
  221. - " pass"
  222. - ' print("deleting objects")'
  223. - " client.delete_objects(Bucket=bucket, Delete={'Objects':
  224. objects})"
  225. - " # objects = []"
  226. - " except:"
  227. - " pass"
  228. - ' print("bucket already empty")'
  229. - ''
  230. - ''
  231. - ''
  232. - 'def timeout(event, context):'
  233. - " logging.error('Execution is about to time out, sending failure
  234. response to CloudFormation')"
  235. - " cfnresponse.send(event, context, cfnresponse.FAILED, {}, None)"
  236. - ''
  237. - ''
  238. - 'def handler(event, context):'
  239. - " # make sure we send a failure to CloudFormation if the function
  240. is going to timeout"
  241. - " timer = threading.Timer((context.get_remaining_time_in_millis()
  242. / 1000.00) - 0.5, timeout, args=[event, context])"
  243. - " timer.start()"
  244. - ''
  245. - " print(('Received event: %s' % json.dumps(event)))"
  246. - " status = cfnresponse.SUCCESS"
  247. - " try:"
  248. - " dest_bucket = event['ResourceProperties']['DestBucket']"
  249. - " if event['RequestType'] == 'Delete':"
  250. - " CheckifVersioned = client.get_bucket_versioning(Bucket=dest_bucket)"
  251. - " print(CheckifVersioned)"
  252. - " if 'Status' in CheckifVersioned:"
  253. - " print(CheckifVersioned['Status'])"
  254. - ' print ("This is a versioned Bucket")'
  255. - " delete_versionedobjects(dest_bucket)"
  256. - " else:"
  257. - ' print("This is not a versioned bucket")'
  258. - " delete_NonVersionedobjects(dest_bucket)"
  259. - " else:"
  260. - ' print("Nothing to do")'
  261. - " except Exception as e:"
  262. - " logging.error('Exception: %s' % e, exc_info=True)"
  263. - " status = cfnresponse.FAILED"
  264. - " finally:"
  265. - " timer.cancel()"
  266. - " cfnresponse.send(event, context, status, {}, None)"
  267. - ''
  268. Description: Empty the S3 Bucket
  269. Handler: index.handler
  270. Role:
  271. Fn::GetAtt:
  272. - S3CleanUpRole
  273. - Arn
  274. Runtime: python3.7
  275. Timeout: 240
  276. Type: AWS::Lambda::Function
  277. S3CleanUpRole:
  278. Properties:
  279. AssumeRolePolicyDocument:
  280. Statement:
  281. - Action: sts:AssumeRole
  282. Effect: Allow
  283. Principal:
  284. Service: lambda.amazonaws.com
  285. Version: '2012-10-17'
  286. ManagedPolicyArns:
  287. - !Sub arn:${AWS::Partition}:iam::${AWS::Partition}:policy/service-role/AWSLambdaBasicExecutionRole
  288. Path: "/"
  289. Policies:
  290. - PolicyDocument:
  291. Statement:
  292. - Action:
  293. - s3:PutObject
  294. - s3:DeleteObject
  295. - s3:GetObject
  296. - s3:ListBucket
  297. - s3:ListBucketVersions
  298. - s3:DeleteObjectVersion
  299. - s3:GetObjectVersion
  300. - s3:GetBucketVersioning
  301. Effect: Allow
  302. Resource:
  303. - Fn::GetAtt:
  304. - LambdaZipsBucket
  305. - Arn
  306. - Fn::Sub: arn:${AWS::Partition}:s3:::*
  307. Version: '2012-10-17'
  308. PolicyName: Empty-bucket
  309. Type: AWS::IAM::Role
  310. Outputs:
  311. LambdaZipsBucket:
  312. Description: S3 Bucket for the Lambda Function Code
  313. Value:
  314. Ref: LambdaZipsBucket