import AWS from 'aws-sdk' ; import moment from 'moment' ; import { ListObjectsV2Output } from 'aws-sdk/clients/s3' ; export interface LogStreamType { logStreamName : string ; firstEventTimestamp : number ; lastEventTimestamp : number ; } export class AuditLogMoverHelper { static async doesEachDayHaveS3Directory ( eachDayInTimeFrame , auditLogBucket ) { const yearAndMonthPrefixOfDates = Array . from ( new Set ( eachDayInTimeFrame . map ( ( date ) => { return date . substring ( 0 , 7 ) ; } ) ) ) ; const directoriesInS3 = await this . getDirectoriesInS3GivenPrefixes ( yearAndMonthPrefixOfDates , auditLogBucket ) ; const dateWithoutDirectory = eachDayInTimeFrame . filter ( ( date ) => ! directoriesInS3 . includes ( date ) ) ; return dateWithoutDirectory . length === 0 ; } static getEachDayInTimeFrame ( startTimeMoment , endTimeMoment ) { if ( startTimeMoment . isAfter ( endTimeMoment ) ) { throw new Error ( 'startTime can not be later than endTime' ) ; } const eachDayInTimeFrame = [ ] ; let currentTimeMoment = moment ( startTimeMoment ) ; do { eachDayInTimeFrame . push ( moment ( currentTimeMoment ) ) ; currentTimeMoment = currentTimeMoment . add ( 1 , 'days' ) ; } while ( currentTimeMoment . valueOf ( ) < endTimeMoment . valueOf ( ) ) ; return eachDayInTimeFrame ; } private static async getDirectoriesInS3GivenPrefixes ( prefixes , auditLogBucket ) { const S3 = new AWS . S3 ( ) ; const listS3Responses = await Promise . all ( prefixes . map ( ( prefix ) => { const s3params = { Bucket : auditLogBucket , MaxKeys : 31 , Delimiter : '/' , Prefix : prefix , } ; return S3 . listObjectsV2 ( s3params ) . promise ( ) ; } ) ) ; const directoriesInS3 = [ ] ; listS3Responses . forEach ( ( response ) => { if ( response . CommonPrefixes ) { response . CommonPrefixes . forEach ( ( commonPrefix ) => { if ( commonPrefix . Prefix ) { directoriesInS3 . push ( commonPrefix . Prefix . slice ( 0 , - 1 ) ) ; } } ) ; } } ) ; return directoriesInS3 ; } static async getAllLogStreams ( cwLogExecutionGroup ) { const params = { logGroupName : cwLogExecutionGroup , orderBy : 'LastEventTime' , descending : true , limit : 50 , } ; const logStreams = [ ] ; let nextToken = '' ; do { if ( nextToken ) { params . nextToken = nextToken ; } const cloudwatchLogs = new AWS . CloudWatchLogs ( ) ; const describeResponse = await cloudwatchLogs . describeLogStreams ( params ) . promise ( ) ; if ( describeResponse . logStreams && describeResponse . logStreams . length > 0 ) { describeResponse . logStreams . forEach ( ( logStream ) => { logStreams . push ( { logStreamName : logStream . logStreamName , firstEventTimestamp : logStream . firstEventTimestamp , lastEventTimestamp : logStream . lastEventTimestamp , } ) ; } ) ; } nextToken = describeResponse . nextToken || '' ; } while ( nextToken ) ; return logStreams ; } static async putCWMetric ( stage , functionName , isSuccessful ) { const putMetricDataPromises = [ ] ; if ( isSuccessful ) { putMetricDataPromises . push ( this . getMetricDataPromise ( stage , functionName , true , 1 ) ) ; putMetricDataPromises . push ( this . getMetricDataPromise ( stage , functionName , false , 0 ) ) ; } else { putMetricDataPromises . push ( this . getMetricDataPromise ( stage , functionName , true , 0 ) ) ; putMetricDataPromises . push ( this . getMetricDataPromise ( stage , functionName , false , 1 ) ) ; } try { await Promise . all ( putMetricDataPromises ) ; } catch ( e ) { console . error ( 'Failed to putCWMetric' , e ) ; } } private static async getMetricDataPromise ( stage , functionName , isSuccessful , metricValue ) { const MetricName = `${ functionName }-${ isSuccessful ? 'Succeeded' : 'Failed' }` ; const params = { MetricData : [ { MetricName , Dimensions : [ { Name : 'Stage' , Value : stage , } , ] , StorageResolution : 60 , Timestamp : new Date ( ) , Unit : 'Count' , Value : metricValue , } , ] , Namespace : 'Audit-Log-Mover' , } ; const cloudwatch = new AWS . CloudWatch ( ) ; return cloudwatch . putMetricData ( params ) . promise ( ) ; } }